Subject: Collected Debian patches for libhybris
Author: Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>

The libhybris package is maintained in Git rather than maintaining
patches as separate files, and separating the patches doesn't seem to
be worth the effort.  They are therefore all included in this single
Debian patch.

For full commit history and separated commits, see the packaging Git
repository.
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/Android.common.mk
@@ -0,0 +1,10 @@
+# define ANDROID_VERSION MAJOR, MINOR and PATCH
+
+ANDROID_VERSION_MAJOR := $(word 1, $(subst ., , $(PLATFORM_VERSION)))
+ANDROID_VERSION_MINOR := $(word 2, $(subst ., , $(PLATFORM_VERSION)))
+ANDROID_VERSION_PATCH := $(word 3, $(subst ., , $(PLATFORM_VERSION)))
+
+LOCAL_CFLAGS += \
+	-DANDROID_VERSION_MAJOR=$(ANDROID_VERSION_MAJOR) \
+	-DANDROID_VERSION_MINOR=$(ANDROID_VERSION_MINOR) \
+	-DANDROID_VERSION_PATCH=$(ANDROID_VERSION_PATCH)
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/camera/Android.mk
+++ libhybris-0.1.0+git20151016+6d424c9/compat/camera/Android.mk
@@ -1,5 +1,6 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
+include $(LOCAL_PATH)/../Android.common.mk
 
 HYBRIS_PATH := $(LOCAL_PATH)/../../hybris
 
@@ -7,6 +8,7 @@ LOCAL_SRC_FILES := camera_compatibility_
 
 LOCAL_MODULE := libcamera_compat_layer
 LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
 
 LOCAL_C_INCLUDES := \
 	$(HYBRIS_PATH)/include
@@ -30,6 +32,7 @@ LOCAL_SRC_FILES := direct_camera_test.cp
 
 LOCAL_MODULE := direct_camera_test
 LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
 
 LOCAL_C_INCLUDES := \
 	$(HYBRIS_PATH)/include \
@@ -43,6 +46,7 @@ LOCAL_SHARED_LIBRARIES := \
 	libis_compat_layer \
 	libsf_compat_layer \
 	libcamera_compat_layer \
+	libmedia_compat_layer \
 	libcutils \
 	libcamera_client \
 	libutils \
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/camera/camera_compatibility_layer.cpp
+++ libhybris-0.1.0+git20151016+6d424c9/compat/camera/camera_compatibility_layer.cpp
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2013 Canonical Ltd
+ * Copyright (C) 2013-2014 Canonical Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,9 +14,12 @@
  * limitations under the License.
  *
  * Authored by: Thomas Voß <thomas.voss@canonical.com>
- *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ *				Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ *				Jim Hodapp <jim.hodapp@canonical.com>
  */
 
+//#define LOG_NDEBUG 0
+
 #include <hybris/internal/camera_control.h>
 #include <hybris/camera/camera_compatibility_layer.h>
 #include <hybris/camera/camera_compatibility_layer_capabilities.h>
@@ -27,18 +30,41 @@
 #include <binder/ProcessState.h>
 #include <camera/Camera.h>
 #include <camera/CameraParameters.h>
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
 #include <gui/SurfaceTexture.h>
+#else
+#include <gui/GLConsumer.h>
+#endif
+#if ANDROID_VERSION_MAJOR==5
+#include <gui/IGraphicBufferProducer.h>
+#endif
 #include <ui/GraphicBuffer.h>
 
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
 #undef LOG_TAG
 #define LOG_TAG "CameraCompatibilityLayer"
+#include <utils/Debug.h>
+#include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/Log.h>
+#include <utils/String16.h>
+
+#include <gui/NativeBufferAlloc.h>
+
+#include <cstring>
 
 #define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__)
 
-// From android::SurfaceTexture::FrameAvailableListener
-void CameraControl::onFrameAvailable()
+using android::CompileTimeAssert; // So COMPILE_TIME_ASSERT works
+
+// From android::GLConsumer::FrameAvailableListener
+#if ANDROID_VERSION_MAJOR==5 && ANDROID_VERSION_MINOR>=1
+  void CameraControl::onFrameAvailable(const android::BufferItem& item)
+#else
+  void CameraControl::onFrameAvailable()
+#endif
 {
 	REPORT_FUNCTION();
 	if (listener)
@@ -95,6 +121,9 @@ void CameraControl::postData(
 		if (listener->on_data_compressed_image_cb)
 			listener->on_data_compressed_image_cb(data->pointer(), data->size(), listener->context);
 		break;
+	case CAMERA_MSG_PREVIEW_FRAME:
+		if (listener->on_preview_frame_cb)
+			listener->on_preview_frame_cb(data->pointer(), data->size(), listener->context);
 	default:
 		break;
 	}
@@ -137,54 +166,80 @@ sp<GraphicBuffer> NativeBufferAlloc::cre
 }
 }
 
-namespace
+int android_camera_get_number_of_devices()
 {
-
-android::sp<CameraControl> camera_control_instance;
-
+	REPORT_FUNCTION();
+	return android::Camera::getNumberOfCameras();
 }
 
-int android_camera_get_number_of_devices()
+int android_camera_get_device_info(int32_t camera_id, int* facing, int* orientation)
 {
 	REPORT_FUNCTION();
-	return android::Camera::getNumberOfCameras();
+
+	if (!facing || !orientation)
+		return android::BAD_VALUE;
+
+	COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CAMERA_FACING_BACK == static_cast<int>(BACK_FACING_CAMERA_TYPE));
+	COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CAMERA_FACING_FRONT == static_cast<int>(FRONT_FACING_CAMERA_TYPE));
+
+	android::CameraInfo ci;
+
+	int rv = android::Camera::getCameraInfo(camera_id, &ci);
+	if (rv != android::OK)
+		return rv;
+
+	*facing = ci.facing;
+	*orientation = ci.orientation;
+
+	return android::OK;
 }
 
 CameraControl* android_camera_connect_to(CameraType camera_type, CameraControlListener* listener)
 {
 	REPORT_FUNCTION();
 
-	int32_t camera_id;
-	int32_t camera_count = camera_id = android::Camera::getNumberOfCameras();
+	const int32_t camera_count = android::Camera::getNumberOfCameras();
 
-	for (camera_id = 0; camera_id < camera_count; camera_id++) {
+	for (int32_t camera_id = 0; camera_id < camera_count; camera_id++) {
 		android::CameraInfo ci;
 		android::Camera::getCameraInfo(camera_id, &ci);
 
-		if (ci.facing == camera_type)
-			break;
+		if (ci.facing != camera_type)
+			continue;
+
+		return android_camera_connect_by_id(camera_id, listener);
 	}
 
-	if (camera_id == camera_count)
+	return NULL;
+}
+
+CameraControl* android_camera_connect_by_id(int32_t camera_id, struct CameraControlListener* listener)
+{
+	if (camera_id < 0 || camera_id >= android::Camera::getNumberOfCameras())
 		return NULL;
 
-	CameraControl* cc = new CameraControl();
+	android::sp<CameraControl> cc = new CameraControl();
 	cc->listener = listener;
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR>=3 || ANDROID_VERSION_MAJOR==5
+	cc->camera = android::Camera::connect(camera_id, android::String16("hybris"), android::Camera::USE_CALLING_UID);
+#else
 	cc->camera = android::Camera::connect(camera_id);
+#endif
 
 	if (cc->camera == NULL)
 		return NULL;
 
 	cc->camera_parameters = android::CameraParameters(cc->camera->getParameters());
 
-	camera_control_instance = cc;
-	cc->camera->setListener(camera_control_instance);
+	// android::Camera holds a strong reference to the listener, keeping
+	// |cc| alive
+	cc->camera->setListener(cc);
 	cc->camera->lock();
 
 	// TODO: Move this to a more generic component
 	android::ProcessState::self()->startThreadPool();
 
-	return cc;
+	return cc.get();
 }
 
 void android_camera_disconnect(CameraControl* control)
@@ -215,7 +270,9 @@ int android_camera_unlock(CameraControl*
 
 void android_camera_delete(CameraControl* control)
 {
-	delete control;
+	android::sp<android::Camera> camera = control->camera;
+	control->camera.clear();
+	camera.clear();
 }
 
 void android_camera_dump_parameters(CameraControl* control)
@@ -252,6 +309,35 @@ void android_camera_get_flash_mode(Camer
 		*mode = FLASH_MODE_OFF;
 }
 
+void android_camera_enumerate_supported_flash_modes(CameraControl* control, flash_mode_callback cb, void* ctx)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+	android::String8 raw_modes;
+	raw_modes = android::String8(
+			control->camera_parameters.get(
+				android::CameraParameters::KEY_SUPPORTED_FLASH_MODES));
+
+	const char delimiter[2] = ",";
+	char *token;
+	android::String8 mode;
+	char *raw_modes_mutable = strdup(raw_modes.string());
+
+	token = strtok(raw_modes_mutable, delimiter);
+
+	while (token != NULL) {
+		uint32_t index = flash_modes_lut.indexOfKey(mode);
+
+		mode = android::String8(token);
+		if (flash_modes_lut.indexOfKey(mode) >= 0) {
+			cb(ctx, flash_modes_lut.valueFor(mode));
+		}
+		token = strtok(NULL, delimiter);
+	}
+}
+
 void android_camera_set_white_balance_mode(CameraControl* control, WhiteBalanceMode mode)
 {
 	REPORT_FUNCTION();
@@ -291,6 +377,31 @@ void android_camera_set_scene_mode(Camer
 	control->camera->setParameters(control->camera_parameters.flatten());
 }
 
+void android_camera_enumerate_supported_scene_modes(CameraControl* control, scene_mode_callback cb, void* ctx)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+	android::String8 raw_modes;
+	raw_modes = android::String8(
+					control->camera_parameters.get(
+						android::CameraParameters::KEY_SUPPORTED_SCENE_MODES));
+
+	const char delimiter[2] = ",";
+	char *token;
+	android::String8 mode;
+	char *raw_modes_mutable = strdup(raw_modes.string());
+
+	token = strtok(raw_modes_mutable, delimiter);
+
+	while (token != NULL) {
+		mode = android::String8(token);
+		cb(ctx, scene_modes_lut.valueFor(mode));
+		token = strtok(NULL, delimiter);
+	}
+}
+
 void android_camera_get_scene_mode(CameraControl* control, SceneMode* mode)
 {
 	REPORT_FUNCTION();
@@ -445,6 +556,67 @@ void android_camera_get_picture_size(Cam
 	control->camera_parameters.getPictureSize(width, height);
 }
 
+void android_camera_set_thumbnail_size(struct CameraControl* control, int width, int height)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+
+	control->camera_parameters.set(
+			android::CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH,
+			width);
+	control->camera_parameters.set(
+			android::CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT,
+			height);
+	control->camera->setParameters(control->camera_parameters.flatten());
+}
+
+void android_camera_get_thumbnail_size(struct CameraControl* control, int* width, int* height)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+
+	*width = atoi(control->camera_parameters.get(android::CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH));
+	*height = atoi(control->camera_parameters.get(android::CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT));
+}
+
+void android_camera_enumerate_supported_thumbnail_sizes(struct CameraControl* control, size_callback cb, void* ctx)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+	// e.g. 800x600,320x240
+	android::String8 sizes = android::String8(
+			control->camera_parameters.get(
+				android::CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES));
+
+	const char delimiter[2] = ",";
+	const char size_delimiter[2] = "x";
+	char *token, *save_ptr, *save_ptr1;
+	int height = 0, width = 0;
+	char *sizes_mutable = strdup(sizes.string());
+
+	ALOGD("Supported thumbnail sizes: %s", sizes.string());
+	// Get the first <width>x<height to the left of ','
+	token = strtok_r(sizes_mutable, delimiter, &save_ptr);
+
+	while (token != NULL) {
+		// Parse <width>x<height> token
+		char *w = strtok_r(token, size_delimiter, &save_ptr1);
+		char *h = strtok_r(NULL, size_delimiter, &save_ptr1);
+		width = atoi(w);
+		height = atoi(h);
+		if (width > 0 && height > 0)
+			cb(ctx, width, height);
+		// Get the next <width>x<height> pair
+		token = strtok_r(NULL, delimiter, &save_ptr);
+	}
+}
+
 void android_camera_set_picture_size(CameraControl* control, int width, int height)
 {
 	REPORT_FUNCTION();
@@ -511,30 +683,72 @@ void android_camera_set_preview_texture(
 	assert(control);
 
 	static const bool allow_synchronous_mode = false;
+	static const bool is_controlled_by_app = true;
 
 	android::sp<android::NativeBufferAlloc> native_alloc(
 			new android::NativeBufferAlloc()
 			);
 
+#if ANDROID_VERSION_MAJOR==5
+	android::sp<android::IGraphicBufferProducer> producer;
+	android::sp<android::IGraphicBufferConsumer> consumer;
+	android::BufferQueue::createBufferQueue(&producer, &consumer);
+#else
 	android::sp<android::BufferQueue> buffer_queue(
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
 			new android::BufferQueue(false, NULL, native_alloc)
+#else
+			new android::BufferQueue(NULL)
+#endif
 			);
+#endif
 
 	if (control->preview_texture == NULL) {
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
 		control->preview_texture = android::sp<android::SurfaceTexture>(
 				new android::SurfaceTexture(
+#else
+		control->preview_texture = android::sp<android::GLConsumer>(
+				new android::GLConsumer(
+#endif
+#if ANDROID_VERSION_MAJOR==5
+					consumer,
+					texture_id,
+					GL_TEXTURE_EXTERNAL_OES,
+					true,
+					is_controlled_by_app));
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
 					texture_id,
 					allow_synchronous_mode,
 					GL_TEXTURE_EXTERNAL_OES,
 					true,
 					buffer_queue));
+#else
+					buffer_queue,
+					texture_id,
+					GL_TEXTURE_EXTERNAL_OES,
+					true,
+					is_controlled_by_app));
+#endif
 	}
 
 	control->preview_texture->setFrameAvailableListener(
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
 			android::sp<android::SurfaceTexture::FrameAvailableListener>(control));
+#else
+			android::sp<android::GLConsumer::FrameAvailableListener>(control));
+#endif
+
+#if ANDROID_VERSION_MAJOR==5
+	control->camera->setPreviewTarget(producer);
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
 	control->camera->setPreviewTexture(control->preview_texture->getBufferQueue());
+#else
+	control->camera->setPreviewTarget(buffer_queue);
+#endif
 }
 
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
 void android_camera_set_preview_surface(CameraControl* control, SfSurface* surface)
 {
 	REPORT_FUNCTION();
@@ -544,6 +758,7 @@ void android_camera_set_preview_surface(
 	android::Mutex::Autolock al(control->guard);
 	control->camera->setPreviewDisplay(surface->surface);
 }
+#endif
 
 void android_camera_start_preview(CameraControl* control)
 {
@@ -630,6 +845,22 @@ void android_camera_take_snapshot(Camera
 	control->camera->takePicture(CAMERA_MSG_SHUTTER | CAMERA_MSG_COMPRESSED_IMAGE);
 }
 
+int android_camera_set_preview_callback_mode(CameraControl* control, PreviewCallbackMode mode)
+{
+	REPORT_FUNCTION();
+
+	if (!control)
+		return android::BAD_VALUE;
+
+	android::Mutex::Autolock al(control->guard);
+
+	control->camera->setPreviewCallbackFlags(
+		mode == PREVIEW_CALLBACK_ENABLED ?
+			CAMERA_FRAME_CALLBACK_FLAG_CAMCORDER : CAMERA_FRAME_CALLBACK_FLAG_NOOP);
+
+	return android::OK;
+}
+
 void android_camera_set_preview_format(CameraControl* control, CameraPixelFormat pf)
 {
 	REPORT_FUNCTION();
@@ -690,6 +921,39 @@ void android_camera_reset_focus_region(C
 	android_camera_set_focus_region(control, &region);
 }
 
+void android_camera_set_metering_region(
+                CameraControl* control,
+                MeteringRegion* region)
+{
+        REPORT_FUNCTION();
+        assert(control);
+
+        android::Mutex::Autolock al(control->guard);
+        static const char* metering_region_pattern = "(%d,%d,%d,%d,%d)";
+        static char metering_region[256];
+        snprintf(metering_region,
+                        sizeof(metering_region),
+                        metering_region_pattern,
+                        region->left,
+                        region->top,
+                        region->right,
+                        region->bottom,
+                        region->weight);
+
+        control->camera_parameters.set(
+                        android::CameraParameters::KEY_METERING_AREAS,
+                        metering_region);
+
+        control->camera->setParameters(control->camera_parameters.flatten());
+}
+
+void android_camera_reset_metering_region(CameraControl* control)
+{
+        static FocusRegion region = { 0, 0, 0, 0, 0 };
+
+        android_camera_set_metering_region(control, &region);
+}
+
 void android_camera_set_rotation(CameraControl* control, int rotation)
 {
 	REPORT_FUNCTION();
@@ -702,6 +966,30 @@ void android_camera_set_rotation(CameraC
 	control->camera->setParameters(control->camera_parameters.flatten());
 }
 
+void android_camera_set_location(CameraControl* control, const float* latitude, const float* longitude, const float* altitude, int timestamp, const char* method)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+	control->camera_parameters.setFloat(
+			android::CameraParameters::KEY_GPS_LATITUDE,
+			*latitude);
+	control->camera_parameters.setFloat(
+			android::CameraParameters::KEY_GPS_LONGITUDE,
+			*longitude);
+	control->camera_parameters.setFloat(
+			android::CameraParameters::KEY_GPS_ALTITUDE,
+			*altitude);
+	control->camera_parameters.set(
+			android::CameraParameters::KEY_GPS_TIMESTAMP,
+			timestamp);
+	control->camera_parameters.set(
+			android::CameraParameters::KEY_GPS_PROCESSING_METHOD,
+			method);
+	control->camera->setParameters(control->camera_parameters.flatten());
+}
+
 void android_camera_enumerate_supported_video_sizes(CameraControl* control, size_callback cb, void* ctx)
 {
 	REPORT_FUNCTION();
@@ -737,3 +1025,25 @@ void android_camera_set_video_size(Camer
 	control->camera_parameters.setVideoSize(width, height);
 	control->camera->setParameters(control->camera_parameters.flatten());
 }
+
+void android_camera_set_jpeg_quality(CameraControl* control, int quality)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+	control->camera_parameters.set(
+			android::CameraParameters::KEY_JPEG_QUALITY,
+			quality);
+	control->camera->setParameters(control->camera_parameters.flatten());
+}
+
+void android_camera_get_jpeg_quality(CameraControl* control, int* quality)
+{
+	REPORT_FUNCTION();
+	assert(control);
+
+	android::Mutex::Autolock al(control->guard);
+	*quality = atoi(control->camera_parameters.get(
+            android::CameraParameters::KEY_JPEG_QUALITY));
+}
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/camera/direct_camera_test.cpp
+++ libhybris-0.1.0+git20151016+6d424c9/compat/camera/direct_camera_test.cpp
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2013 Canonical Ltd
+ * Copyright (C) 2013-2014 Canonical Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *		http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,11 +14,13 @@
  * limitations under the License.
  *
  * Authored by: Thomas Voß <thomas.voss@canonical.com>
- *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ *				Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ *				Jim Hodapp <jim.hodapp@canonical.com>
  */
 
 #include <hybris/camera/camera_compatibility_layer.h>
 #include <hybris/camera/camera_compatibility_layer_capabilities.h>
+#include <hybris/media/media_recorder_layer.h>
 
 #include <hybris/input/input_stack_compatibility_layer.h>
 #include <hybris/input/input_stack_compatibility_layer_codes_key.h>
@@ -45,6 +47,11 @@
 int shot_counter = 1;
 int32_t current_zoom_level = 1;
 bool new_camera_frame_available = true;
+static CameraControl* camera_control = NULL;
+int camera_width = 0, camera_height = 0;
+int thumbnail_width = 0, thumbnail_height = 0;
+static MediaRecorderWrapper *recorder = NULL;
+bool recording = false;
 
 EffectMode next_effect()
 {
@@ -122,7 +129,7 @@ void jpeg_data_cb(void* data, uint32_t d
 	printf("%s: %d \n", __PRETTY_FUNCTION__, data_size);
 
 	char fn[256];
-	sprintf(fn, "/data/shot_%d.jpeg", shot_counter);
+	sprintf(fn, "/cache/shot_%d.jpeg", shot_counter);
 	int fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
 	write(fd, data, data_size);
 	close(fd);
@@ -135,131 +142,54 @@ void jpeg_data_cb(void* data, uint32_t d
 void size_cb(void* ctx, int width, int height)
 {
 	printf("Supported size: [%d,%d]\n", width, height);
+	if (width == 1024 && height == 768) {
+		camera_width = 1024;
+		camera_height = 768;
+	}
 }
 
-void preview_texture_needs_update_cb(void* ctx)
-{
-	new_camera_frame_available = true;
-}
-
-void on_new_input_event(Event* event, void* context)
-{
-    assert(context);
-
-    if (event->type == KEY_EVENT_TYPE && event->action == ISCL_KEY_EVENT_ACTION_UP) {
-	    printf("We have got a key event: %d \n", event->details.key.key_code);
-
-	    CameraControl* cc = static_cast<CameraControl*>(context);
-
-	    switch(event->details.key.key_code) {
-	    case ISCL_KEYCODE_VOLUME_UP:
-		    printf("\tZooming in now.\n");
-		    android_camera_start_zoom(cc, current_zoom_level+1);
-		    break;
-	    case ISCL_KEYCODE_VOLUME_DOWN:
-		    printf("\tZooming out now.\n");
-		    android_camera_start_zoom(cc, current_zoom_level-1);
-		    break;
-	    case ISCL_KEYCODE_POWER:
-		    printf("\tTaking a photo now.\n");
-		    android_camera_take_snapshot(cc);
-		    break;
-	    case ISCL_KEYCODE_HEADSETHOOK:
-		    printf("\tSwitching effect.\n");
-		    android_camera_set_effect_mode(cc, next_effect());
-	    }
-    } else if (event->type == MOTION_EVENT_TYPE &&
-		    event->details.motion.pointer_count == 1) {
-	    if ((event->action & ISCL_MOTION_EVENT_ACTION_MASK) == ISCL_MOTION_EVENT_ACTION_UP) {
-		    printf("\tMotion event(Action up): (%f, %f) \n",
-				    event->details.motion.pointer_coordinates[0].x,
-				    event->details.motion.pointer_coordinates[0].y);
-	    }
-
-	    if ((event->action & ISCL_MOTION_EVENT_ACTION_MASK) == ISCL_MOTION_EVENT_ACTION_DOWN) {
-		    printf("\tMotion event(Action down): (%f, %f) \n",
-				    event->details.motion.pointer_coordinates[0].x,
-				    event->details.motion.pointer_coordinates[0].y);
-	    }
-    }
-}
-
-struct ClientWithSurface
-{
-	SfClient* client;
-	SfSurface* surface;
-};
-
-ClientWithSurface client_with_surface(bool setup_surface_with_egl)
+void thumbnail_size_cb(void* ctx, int width, int height)
 {
-	ClientWithSurface cs = ClientWithSurface();
-
-	cs.client = sf_client_create();
-
-	if (!cs.client) {
-		printf("Problem creating client ... aborting now.");
-		return cs;
+	static bool do_once = true;
+	printf("Supported thumbnail size: [%d,%d]\n", width, height);
+	if (do_once) {
+		printf("Selecting thumbnail size: [%dx%d]\n", width, height);
+		thumbnail_width = width;
+		thumbnail_height = height;
 	}
-
-	static const size_t primary_display = 0;
-
-	SfSurfaceCreationParameters params = {
-		0,
-		0,
-		(int) sf_get_display_width(primary_display),
-		(int) sf_get_display_height(primary_display),
-		-1, //PIXEL_FORMAT_RGBA_8888,
-		15000,
-		0.5f,
-		setup_surface_with_egl, // Do not associate surface with egl, will be done by camera HAL
-		"CameraCompatLayerTestSurface"
-	};
-
-	cs.surface = sf_surface_create(cs.client, &params);
-
-	if (!cs.surface) {
-		printf("Problem creating surface ... aborting now.");
-		return cs;
-	}
-
-	sf_surface_make_current(cs.surface);
-
-	return cs;
 }
 
-#define PRINT_GLERROR() printf("GL error@%d: %x\n", __LINE__, glGetError());
-
 struct RenderData
 {
 	static const char* vertex_shader()
 	{
 		return
-			"#extension GL_OES_EGL_image_external : require              \n"
-			"attribute vec4 a_position;                                  \n"
-			"attribute vec2 a_texCoord;                                  \n"
-			"uniform mat4 m_texMatrix;                                   \n"
-			"varying vec2 v_texCoord;                                    \n"
-			"varying float topDown;                                      \n"
-			"void main()                                                 \n"
-			"{                                                           \n"
-			"   gl_Position = a_position;                                \n"
-			"   v_texCoord = a_texCoord;                                 \n"
-			//                "   v_texCoord = (m_texMatrix * vec4(a_texCoord, 0.0, 1.0)).xy;\n"
-			//"   topDown = v_texCoord.y;                                  \n"
-			"}                                                           \n";
+			"#extension GL_OES_EGL_image_external : require				 \n"
+			"attribute vec4 a_position;									 \n"
+			"attribute vec2 a_texCoord;									 \n"
+			"uniform mat4 m_texMatrix;									 \n"
+			"varying vec2 v_texCoord;									 \n"
+			"varying float topDown;										 \n"
+			"void main()												 \n"
+			"{															 \n"
+			"	gl_Position = a_position;								 \n"
+			"	v_texCoord = a_texCoord;								 \n"
+			//				  "   v_texCoord = (m_texMatrix * vec4(a_texCoord, 0.0, 1.0)).xy;\n"
+			//"   topDown = v_texCoord.y;								   \n"
+			"}															 \n";
 	}
 
 	static const char* fragment_shader()
 	{
 		return
-			"#extension GL_OES_EGL_image_external : require      \n"
-			"precision mediump float;                            \n"
-			"varying vec2 v_texCoord;                            \n"
-			"uniform samplerExternalOES s_texture;               \n"
-			"void main()                                         \n"
-			"{                                                   \n"
+			"#extension GL_OES_EGL_image_external : require		 \n"
+			"precision mediump float;							 \n"
+			"varying vec2 v_texCoord;							 \n"
+			"uniform samplerExternalOES s_texture;				 \n"
+			"void main()										 \n"
+			"{													 \n"
 			"  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
-			"}                                                   \n";
+			"}													 \n";
 	}
 
 	static GLuint loadShader(GLenum shaderType, const char* pSource)
@@ -354,6 +284,254 @@ struct RenderData
 	GLint matrix_loc;
 };
 
+
+static RenderData render_data;
+static EGLDisplay disp;
+static EGLSurface surface;
+
+void preview_texture_needs_update_cb(void* ctx)
+{
+	ALOGD("Updating preview texture");
+	new_camera_frame_available = true;
+	static GLfloat vVertices[] = { 0.0f, 0.0f, 0.0f, // Position 0
+		0.0f, 0.0f, // TexCoord 0
+		0.0f, 1.0f, 0.0f, // Position 1
+		0.0f, 1.0f, // TexCoord 1
+		1.0f, 1.0f, 0.0f, // Position 2
+		1.0f, 1.0f, // TexCoord 2
+		1.0f, 0.0f, 0.0f, // Position 3
+		1.0f, 0.0f // TexCoord 3
+	};
+
+	GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+	// Set the viewport
+	// Clear the color buffer
+	glClear(GL_COLOR_BUFFER_BIT);
+	// Use the program object
+	glUseProgram(render_data.program_object);
+	// Enable attributes
+	glEnableVertexAttribArray(render_data.position_loc);
+	glEnableVertexAttribArray(render_data.tex_coord_loc);
+	// Load the vertex position
+	glVertexAttribPointer(render_data.position_loc,
+			3,
+			GL_FLOAT,
+			GL_FALSE,
+			5 * sizeof(GLfloat),
+			vVertices);
+	// Load the texture coordinate
+	glVertexAttribPointer(render_data.tex_coord_loc,
+			2,
+			GL_FLOAT,
+			GL_FALSE,
+			5 * sizeof(GLfloat),
+			vVertices+3);
+
+	glActiveTexture(GL_TEXTURE0);
+	// Set the sampler texture unit to 0
+	glUniform1i(render_data.sampler_loc, 0);
+	glUniform1i(render_data.matrix_loc, 0);
+	ALOGD("Updating the preview texture");
+	if (camera_control != NULL)
+		android_camera_update_preview_texture(camera_control);
+	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+	glDisableVertexAttribArray(render_data.position_loc);
+	glDisableVertexAttribArray(render_data.tex_coord_loc);
+
+	eglSwapBuffers(disp, surface);
+}
+
+static void errorCB(void *context)
+{
+	ALOGE("Error while recording.");
+}
+
+static MediaRecorderWrapper *start_video_recording(CameraControl *camera_control)
+{
+	int ret = 0;
+	struct MediaRecorderWrapper *recorder = android_media_new_recorder();
+	android_recorder_set_error_cb(recorder, &errorCB, NULL);
+
+	ALOGD("Unlocking camera");
+	android_camera_unlock(camera_control);
+	if (recorder == NULL)
+		ALOGW("recorder is NULL: %d", __LINE__);
+
+	ret = android_recorder_setCamera(recorder, camera_control);
+	if (ret < 0) {
+		ALOGE("android_recorder_setCamera() failed");
+		return NULL;
+	}
+	ret = android_recorder_setAudioSource(recorder, ANDROID_AUDIO_SOURCE_CAMCORDER);
+	if (ret < 0) {
+		ALOGE("android_recorder_setAudioSource() failed");
+		return NULL;
+	}
+	ret = android_recorder_setVideoSource(recorder, ANDROID_VIDEO_SOURCE_CAMERA);
+	if (ret < 0) {
+		ALOGE("android_recorder_setVideoSource() failed");
+		return NULL;
+	}
+	ret = android_recorder_setOutputFormat(recorder, ANDROID_OUTPUT_FORMAT_MPEG_4);
+	if (ret < 0) {
+		ALOGE("android_recorder_setOutputFormat() failed");
+		return NULL;
+	}
+	ret = android_recorder_setAudioEncoder(recorder, ANDROID_AUDIO_ENCODER_AAC);
+	if (ret < 0) {
+		ALOGE("android_recorder_setAudioEncoder() failed");
+		return NULL;
+	}
+	ret = android_recorder_setVideoEncoder(recorder, ANDROID_VIDEO_ENCODER_H264);
+	if (ret < 0) {
+		ALOGE("android_recorder_setVideoEncoder() failed");
+		return NULL;
+	}
+	int fd = -1;
+	char *out_file = "/cache/test_recording.mp4";
+	fd = open(out_file, O_WRONLY | O_CREAT,
+			  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+	if (fd < 0) {
+		ALOGE("Couldn't open output video file for recording: %s", out_file);
+		return NULL;
+	}
+	ret = android_recorder_setOutputFile(recorder, fd);
+	if (ret < 0) {
+		ALOGE("android_recorder_setOutputFile() failed");
+		return NULL;
+	}
+	ret = android_recorder_setVideoSize(recorder, camera_width, camera_height);
+	if (ret < 0) {
+		ALOGE("android_recorder_setVideoSize() failed");
+		return NULL;
+	}
+	ret = android_recorder_setVideoFrameRate(recorder, 30);
+	if (ret < 0) {
+		ALOGE("android_recorder_setVideoFrameRate() failed");
+		return NULL;
+	}
+	android_recorder_setParameters(recorder, "video-param-encoding-bitrate=5505024"); // 7*1024*768
+	android_recorder_setParameters(recorder, "audio-param-encoding-bitrate=48000");
+	android_recorder_setParameters(recorder, "audio-param-number-of-channels=2");
+	android_recorder_setParameters(recorder, "audio-param-sampling-rate=96000");
+	android_recorder_setParameters(recorder, "video-param-rotation-angle-degrees=90");
+	ALOGD("Preparing video recording");
+	ret = android_recorder_prepare(recorder);
+	if (ret < 0) {
+		ALOGE("android_recorder_prepare() failed");
+		return NULL;
+	}
+	ALOGD("Starting video recording");
+	ret = android_recorder_start(recorder);
+	if (ret < 0) {
+		ALOGE("android_recorder_start() failed");
+		return NULL;
+	}
+
+	return recorder;
+}
+
+static void stop_video_recording(MediaRecorderWrapper *recorder)
+{
+	if (recording) {
+		ALOGD("Stopping video recording");
+		android_recorder_stop(recorder);
+		android_recorder_reset(recorder);
+		android_recorder_release(recorder);
+		ALOGD("Stopped video recording");
+	}
+}
+
+void on_new_input_event(Event* event, void* context)
+{
+	assert(context);
+
+	if (event->type == KEY_EVENT_TYPE && event->action == ISCL_KEY_EVENT_ACTION_UP) {
+		printf("We got a key event: %d \n", event->details.key.key_code);
+
+		CameraControl* cc = static_cast<CameraControl*>(context);
+
+		switch(event->details.key.key_code) {
+		case ISCL_KEYCODE_VOLUME_UP:
+			printf("Starting video recording to /cache/test_recording.mp4\n");
+			start_video_recording(cc);
+			recording = true;
+			break;
+		case ISCL_KEYCODE_VOLUME_DOWN:
+			printf("Stopping video recording\n");
+			stop_video_recording(recorder);
+			recording = false;
+			break;
+		case ISCL_KEYCODE_POWER:
+			printf("\tTaking a photo now.\n");
+			android_camera_take_snapshot(cc);
+			break;
+		case ISCL_KEYCODE_HEADSETHOOK:
+			printf("\tSwitching effect.\n");
+			android_camera_set_effect_mode(cc, next_effect());
+		}
+	} else if (event->type == MOTION_EVENT_TYPE &&
+			event->details.motion.pointer_count == 1) {
+		if ((event->action & ISCL_MOTION_EVENT_ACTION_MASK) == ISCL_MOTION_EVENT_ACTION_UP) {
+			printf("\tMotion event(Action up): (%f, %f) \n",
+					event->details.motion.pointer_coordinates[0].x,
+					event->details.motion.pointer_coordinates[0].y);
+		}
+
+		if ((event->action & ISCL_MOTION_EVENT_ACTION_MASK) == ISCL_MOTION_EVENT_ACTION_DOWN) {
+			printf("\tMotion event(Action down): (%f, %f) \n",
+					event->details.motion.pointer_coordinates[0].x,
+					event->details.motion.pointer_coordinates[0].y);
+		}
+	}
+}
+
+struct ClientWithSurface
+{
+	SfClient* client;
+	SfSurface* surface;
+};
+
+ClientWithSurface client_with_surface(bool setup_surface_with_egl)
+{
+	ClientWithSurface cs = ClientWithSurface();
+
+	cs.client = sf_client_create();
+
+	if (!cs.client) {
+		printf("Problem creating client ... aborting now.");
+		return cs;
+	}
+
+	static const size_t primary_display = 0;
+
+	SfSurfaceCreationParameters params = {
+		0,
+		0,
+		(int) sf_get_display_width(primary_display),
+		(int) sf_get_display_height(primary_display),
+		-1, //PIXEL_FORMAT_RGBA_8888,
+		15000,
+		0.5f,
+		setup_surface_with_egl, // Do not associate surface with egl, will be done by camera HAL
+		"CameraCompatLayerTestSurface"
+	};
+
+	cs.surface = sf_surface_create(cs.client, &params);
+
+	if (!cs.surface) {
+		printf("Problem creating surface ... aborting now.");
+		return cs;
+	}
+
+	sf_surface_make_current(cs.surface);
+
+	return cs;
+}
+
+#define PRINT_GLERROR() printf("GL error@%d: %x\n", __LINE__, glGetError());
+
 int main(int argc, char** argv)
 {
 	CameraControlListener listener;
@@ -366,80 +544,112 @@ int main(int argc, char** argv)
 	listener.on_data_raw_image_cb = raw_data_cb;
 	listener.on_data_compressed_image_cb = jpeg_data_cb;
 	listener.on_preview_texture_needs_update_cb = preview_texture_needs_update_cb;
-	CameraControl* cc = android_camera_connect_to(FRONT_FACING_CAMERA_TYPE,
+	camera_control = android_camera_connect_to(BACK_FACING_CAMERA_TYPE,
 			&listener);
 
-	if (cc == NULL) {
+	if (camera_control == NULL) {
 		printf("Problem connecting to camera");
 		return 1;
 	}
-
-	listener.context = cc;
+	listener.context = camera_control;
 
 	AndroidEventListener event_listener;
 	event_listener.on_new_event = on_new_input_event;
-	event_listener.context = cc;
+	event_listener.context = camera_control;
 
-	InputStackConfiguration input_configuration = { true, 25000 };
+	InputStackConfiguration input_configuration = {
+		enable_touch_point_visualization : true,
+		default_layer_for_touch_point_visualization : 10000,
+		input_area_width : 1024,
+		input_area_height : 1024
+	};
 
 	android_input_stack_initialize(&event_listener, &input_configuration);
 	android_input_stack_start();
 
-	android_camera_dump_parameters(cc);
-	android_camera_enumerate_supported_picture_sizes(cc, size_cb, NULL);
-	android_camera_enumerate_supported_preview_sizes(cc, size_cb, NULL);
+	// Set the still photo size
+	android_camera_enumerate_supported_picture_sizes(camera_control, size_cb, NULL);
+	if (camera_width == 0 && camera_height == 0) {
+		camera_width = 320;
+		camera_height = 240;
+	}
+	android_camera_set_picture_size(camera_control, camera_width, camera_height);
+
+	// Set the still photo thumbnail size
+	android_camera_enumerate_supported_thumbnail_sizes(camera_control, thumbnail_size_cb, NULL);
+	if (thumbnail_width == 0 && thumbnail_height == 0) {
+		thumbnail_width = 320;
+		thumbnail_height = 240;
+	}
+	android_camera_set_thumbnail_size(camera_control, thumbnail_width, thumbnail_height);
+
+	AutoFocusMode af_mode;
+	android_camera_get_auto_focus_mode(camera_control, &af_mode);
+	printf("Current af mode: %d \n", af_mode);
+
+	int zoom;
+	android_camera_set_zoom(camera_control, 0);
+	android_camera_get_max_zoom(camera_control, &zoom);
+	printf("Max zoom: %d \n", zoom);
+
+	android_camera_enumerate_supported_video_sizes(camera_control, size_cb, NULL);
+	android_camera_enumerate_supported_preview_sizes(camera_control, size_cb, NULL);
+	android_camera_set_preview_size(camera_control, camera_width, camera_height);
 
 	int min_fps, max_fps, current_fps;
-	android_camera_get_preview_fps_range(cc, &min_fps, &max_fps);
+	android_camera_get_preview_fps_range(camera_control, &min_fps, &max_fps);
 	printf("Preview fps range: [%d,%d]\n", min_fps, max_fps);
-	android_camera_get_preview_fps(cc, &current_fps);
+	android_camera_get_preview_fps(camera_control, &current_fps);
 	printf("Current preview fps range: %d\n", current_fps);
 
-	android_camera_set_preview_size(cc, 960, 720);
+#if 0
+	android_camera_dump_parameters(camera_control);
+
+	android_camera_set_display_orientation(camera_control, 90);
 
 	int width, height;
-	android_camera_get_preview_size(cc, &width, &height);
+	android_camera_get_preview_size(camera_control, &width, &height);
 	printf("Current preview size: [%d,%d]\n", width, height);
-	android_camera_get_picture_size(cc, &width, &height);
+	android_camera_get_picture_size(camera_control, &width, &height);
 	printf("Current picture size: [%d,%d]\n", width, height);
-	int zoom;
-	android_camera_get_current_zoom(cc, &zoom);
+	android_camera_get_current_zoom(camera_control, &zoom);
 	printf("Current zoom: %d \n", zoom);
-	android_camera_get_max_zoom(cc, &zoom);
-	printf("Max zoom: %d \n", zoom);
 
 	EffectMode effect_mode;
 	FlashMode flash_mode;
 	WhiteBalanceMode wb_mode;
-	SceneMode scene_mode;
-	AutoFocusMode af_mode;
+	//SceneMode scene_mode;
 	CameraPixelFormat pixel_format;
-	android_camera_get_effect_mode(cc, &effect_mode);
-	android_camera_get_flash_mode(cc, &flash_mode);
-	android_camera_get_white_balance_mode(cc, &wb_mode);
-	android_camera_get_scene_mode(cc, &scene_mode);
-	android_camera_get_auto_focus_mode(cc, &af_mode);
-	android_camera_get_preview_format(cc, &pixel_format);
+	android_camera_get_effect_mode(camera_control, &effect_mode);
 	printf("Current effect mode: %d \n", effect_mode);
+	android_camera_get_flash_mode(camera_control, &flash_mode);
 	printf("Current flash mode: %d \n", flash_mode);
-	printf("Current wb mode: %d \n", wb_mode);
+	android_camera_get_white_balance_mode(camera_control, &wb_mode);
+	ALOGD("Current wb mode: %d \n", wb_mode);
+#if 0
+	// Disabled, causes the test app to crash
+	android_camera_get_scene_mode(camera_control, &scene_mode);
 	printf("Current scene mode: %d \n", scene_mode);
-	printf("Current af mode: %d \n", af_mode);
+#endif
+	android_camera_get_preview_format(camera_control, &pixel_format);
 	printf("Current preview pixel format: %d \n", pixel_format);
-	//android_camera_set_focus_region(cc, -200, -200, 200, 200, 300);
+	//android_camera_set_focus_region(camera_control, -200, -200, 200, 200, 300);
+#endif
 
+	printf("Creating client with surface");
 	ClientWithSurface cs = client_with_surface(true /* Associate surface with egl. */);
 
 	if (!cs.surface) {
 		printf("Problem acquiring surface for preview");
 		return 1;
 	}
+	printf("Finished creating client with surface\n");
 
-	EGLDisplay disp = sf_client_get_egl_display(cs.client);
-	EGLSurface surface = sf_surface_get_egl_surface(cs.surface);
+	disp = sf_client_get_egl_display(cs.client);
+	surface = sf_surface_get_egl_surface(cs.surface);
 
-	RenderData render_data;
 	GLuint preview_texture_id;
+	printf("Getting a texture id\n");
 	glGenTextures(1, &preview_texture_id);
 	glClearColor(1.0, 0., 0.5, 1.);
 	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -448,68 +658,26 @@ int main(int argc, char** argv)
 			GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 	glTexParameteri(
 			GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-	android_camera_set_preview_texture(cc, preview_texture_id);
-	android_camera_set_effect_mode(cc, EFFECT_MODE_SEPIA);
-	android_camera_set_flash_mode(cc, FLASH_MODE_AUTO);
-	android_camera_set_auto_focus_mode(cc, AUTO_FOCUS_MODE_CONTINUOUS_PICTURE);
-	android_camera_start_preview(cc);
+	printf("About to set preview texture\n");
+	android_camera_set_preview_texture(camera_control, preview_texture_id);
+#if 0
+	android_camera_set_effect_mode(camera_control, EFFECT_MODE_SEPIA);
+	android_camera_set_flash_mode(camera_control, FLASH_MODE_AUTO);
+	android_camera_set_auto_focus_mode(camera_control, AUTO_FOCUS_MODE_CONTINUOUS_PICTURE);
+#endif
+	android_camera_start_preview(camera_control);
 
 	GLfloat transformation_matrix[16];
-	android_camera_get_preview_texture_transformation(cc, transformation_matrix);
+	android_camera_get_preview_texture_transformation(camera_control, transformation_matrix);
 	glUniformMatrix4fv(render_data.matrix_loc, 1, GL_FALSE, transformation_matrix);
 
 	printf("Started camera preview.\n");
 
-	while (true) {
-		/*if (new_camera_frame_available)
-		  {
-		  printf("Updating texture");
-		  new_camera_frame_available = false;
-		  }*/
-		static GLfloat vVertices[] = { 0.0f, 0.0f, 0.0f, // Position 0
-			0.0f, 0.0f, // TexCoord 0
-			0.0f, 1.0f, 0.0f, // Position 1
-			0.0f, 1.0f, // TexCoord 1
-			1.0f, 1.0f, 0.0f, // Position 2
-			1.0f, 1.0f, // TexCoord 2
-			1.0f, 0.0f, 0.0f, // Position 3
-			1.0f, 0.0f // TexCoord 3
-		};
-
-		GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
-
-		// Set the viewport
-		// Clear the color buffer
-		glClear(GL_COLOR_BUFFER_BIT);
-		// Use the program object
-		glUseProgram(render_data.program_object);
-		// Enable attributes
-		glEnableVertexAttribArray(render_data.position_loc);
-		glEnableVertexAttribArray(render_data.tex_coord_loc);
-		// Load the vertex position
-		glVertexAttribPointer(render_data.position_loc,
-				3,
-				GL_FLOAT,
-				GL_FALSE,
-				5 * sizeof(GLfloat),
-				vVertices);
-		// Load the texture coordinate
-		glVertexAttribPointer(render_data.tex_coord_loc,
-				2,
-				GL_FLOAT,
-				GL_FALSE,
-				5 * sizeof(GLfloat),
-				vVertices+3);
-
-		glActiveTexture(GL_TEXTURE0);
-		// Set the sampler texture unit to 0
-		glUniform1i(render_data.sampler_loc, 0);
-		glUniform1i(render_data.matrix_loc, 0);
-		android_camera_update_preview_texture(cc);
-		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
-		glDisableVertexAttribArray(render_data.position_loc);
-		glDisableVertexAttribArray(render_data.tex_coord_loc);
-
-		eglSwapBuffers(disp, surface);
+	while (1) {
+		usleep(50);
 	}
+
+	stop_video_recording(recorder);
+	android_camera_stop_preview(camera_control);
+	android_camera_disconnect(camera_control);
 }
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/input/Android.mk
+++ libhybris-0.1.0+git20151016+6d424c9/compat/input/Android.mk
@@ -1,5 +1,6 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
+include $(LOCAL_PATH)/../Android.common.mk
 
 HYBRIS_PATH := $(LOCAL_PATH)/../../hybris
 
@@ -9,6 +10,7 @@ LOCAL_SRC_FILES:= input_compatibility_la
 
 LOCAL_MODULE:= libis_compat_layer
 LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
 
 LOCAL_SHARED_LIBRARIES := \
 	libinput \
@@ -20,8 +22,24 @@ LOCAL_SHARED_LIBRARIES := \
 
 LOCAL_C_INCLUDES := \
 	$(HYBRIS_PATH)/include \
-	external/skia/include/core \
-	frameworks/base/services/input
+	external/skia/include/core
+
+HAS_LIBINPUTSERVICE := $(shell test $(ANDROID_VERSION_MAJOR) -eq 4 -a $(ANDROID_VERSION_MINOR) -gt 2 && echo true)
+ifeq ($(HAS_LIBINPUTSERVICE),true)
+LOCAL_SHARED_LIBRARIES += libinputservice
+LOCAL_C_INCLUDES += frameworks/base/services/input
+endif
+
+HAS_LIBINPUTFLINGER := $(shell test $(ANDROID_VERSION_MAJOR) -eq 5 && echo true)
+ifeq ($(HAS_LIBINPUTFLINGER),true)
+LOCAL_SHARED_LIBRARIES += libinputflinger libinputservice
+LOCAL_C_INCLUDES += \
+	frameworks/base/libs/input \
+	frameworks/native/services
+endif
+
+
+
 
 include $(BUILD_SHARED_LIBRARY)
 
@@ -36,6 +54,7 @@ LOCAL_SRC_FILES:= \
 
 LOCAL_MODULE:= direct_input_test
 LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
 
 LOCAL_C_INCLUDES := \
 	$(HYBRIS_PATH)/include \
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/input/input_compatibility_layer.cpp
+++ libhybris-0.1.0+git20151016+6d424c9/compat/input/input_compatibility_layer.cpp
@@ -19,8 +19,14 @@
 
 #include <hybris/input/input_stack_compatibility_layer.h>
 
-#include "InputListener.h"
-#include "InputReader.h"
+#if ANDROID_VERSION_MAJOR<=4
+  #include "InputListener.h"
+  #include "InputReader.h"
+#elif ANDROID_VERSION_MAJOR==5
+  #include "inputflinger/InputListener.h"
+  #include "inputflinger/InputReader.h"
+#endif
+
 #include "PointerController.h"
 #include "SpriteController.h"
 #include <gui/ISurfaceComposer.h>
@@ -48,10 +54,20 @@ public:
 
 	DefaultPointerControllerPolicy()
 	{
+#if ANDROID_VERSION_MAJOR<=4
 		bitmap.setConfig(
 				SkBitmap::kARGB_8888_Config,
 				bitmap_width,
 				bitmap_height);
+#elif ANDROID_VERSION_MAJOR==5
+		SkColorType ct = SkBitmapConfigToColorType(SkBitmap::kARGB_8888_Config);
+		bitmap.setInfo(
+				SkImageInfo::Make(bitmap_width,
+					bitmap_height,
+					ct,
+					SkAlphaType::kPremul_SkAlphaType),
+				0);
+#endif
 		bitmap.allocPixels();
 
 		// Icon for spot touches
@@ -142,7 +158,11 @@ public:
 		mInputDevices = inputDevices;
 	}
 
+#if ANDROID_VERSION_MAJOR<=4
 	virtual android::sp<android::KeyCharacterMap> getKeyboardLayoutOverlay(const android::String8& inputDeviceDescriptor) {
+#elif ANDROID_VERSION_MAJOR==5
+	virtual android::sp<android::KeyCharacterMap> getKeyboardLayoutOverlay(const android::InputDeviceIdentifier& identifier) {
+#endif
 		return NULL;
 	}
 
@@ -150,6 +170,12 @@ public:
 		return android::String8::empty();
 	}
 
+#if ANDROID_VERSION_MAJOR==5
+	virtual android::TouchAffineTransformation getTouchAffineTransformation(const android::String8& inputDeviceDescriptor, int32_t surfaceRotation) {
+		return android::TouchAffineTransformation();
+	}
+#endif
+
 private:
 	android::sp<android::Looper> looper;
 	int default_layer_for_touch_point_visualization;
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/Android.mk
@@ -0,0 +1,192 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/../Android.common.mk
+
+LOCAL_SRC_FILES := \
+	camera_service.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcameraservice \
+	libmedialogservice \
+	libcutils \
+	libmedia \
+	libmedia_compat_layer \
+	libmediaplayerservice \
+	libutils \
+	liblog \
+	libbinder
+
+LOCAL_C_INCLUDES := \
+    frameworks/av/media/libmediaplayerservice \
+    frameworks/av/services/medialog \
+    frameworks/av/services/camera/libcameraservice
+
+IS_ANDROID_5 := $(shell test $(ANDROID_VERSION_MAJOR) -eq 5 && echo true)
+ifeq ($(IS_ANDROID_5),true)
+LOCAL_C_INCLUDES += system/media/camera/include
+endif
+
+LOCAL_MODULE := camera_service
+
+LOCAL_32_BIT_ONLY := true
+
+include $(BUILD_EXECUTABLE)
+
+# -------------------------------------------------
+
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/../Android.common.mk
+
+HYBRIS_PATH := $(LOCAL_PATH)/../../hybris
+
+LOCAL_CFLAGS += -std=gnu++0x
+
+ifeq ($(BOARD_HAS_MEDIA_RECORDER_PAUSE),true)
+LOCAL_CFLAGS += -DBOARD_HAS_MEDIA_RECORDER_PAUSE
+endif
+ifeq ($(BOARD_HAS_MEDIA_RECORDER_RESUME),true)
+LOCAL_CFLAGS += -DBOARD_HAS_MEDIA_RECORDER_RESUME
+endif
+
+LOCAL_SRC_FILES:= \
+	media_compatibility_layer.cpp \
+	media_codec_layer.cpp \
+	media_codec_list.cpp \
+	media_format_layer.cpp \
+	surface_texture_client_hybris.cpp \
+	decoding_service.cpp \
+	media_recorder_layer.cpp \
+	media_recorder.cpp \
+	media_recorder_client.cpp \
+	media_recorder_factory.cpp \
+	media_recorder_observer.cpp
+
+LOCAL_MODULE:= libmedia_compat_layer
+LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	libcamera_client \
+	libutils \
+	libbinder \
+	libhardware \
+	libui \
+	libgui \
+	libstagefright \
+	libstagefright_foundation \
+	libEGL \
+	libGLESv2 \
+	libmedia \
+	libaudioutils \
+	libmediaplayerservice
+
+LOCAL_C_INCLUDES := \
+	$(HYBRIS_PATH)/include \
+	frameworks/base/media/libstagefright/include \
+	frameworks/base/include/media/stagefright \
+	frameworks/base/include/media \
+	frameworks/av/media \
+	frameworks/av/media/libstagefright/include \
+	frameworks/av/include \
+	frameworks/native/include \
+	system/media/audio_utils/include \
+	frameworks/av/services/camera/libcameraservice
+
+IS_ANDROID_5 := $(shell test $(ANDROID_VERSION_MAJOR) -eq 5 && echo true)
+ifeq ($(IS_ANDROID_5),true)
+LOCAL_C_INCLUDES += frameworks/native/include/media/openmax
+endif
+
+ifeq ($(strip $(MTK_CAMERA_BSP_SUPPORT)),yes)
+LOCAL_C_INCLUDES += $(TOP)/mediatek/kernel/include/linux/vcodec
+LOCAL_SHARED_LIBRARIES += \
+	libvcodecdrv
+
+LOCAL_C_INCLUDES+= \
+	$(TOP)/$(MTK_PATH_SOURCE)/frameworks-ext/av/media/libmediaplayerservice \
+	$(TOP)/$(MTK_PATH_SOURCE)/frameworks-ext/av/include \
+	$(TOP)/$(MTK_PATH_SOURCE)/frameworks-ext/av/media/libstagefright/include \
+	$(TOP)/$(MTK_PATH_PLATFORM)/frameworks/libmtkplayer \
+	$(TOP)/$(MTK_PATH_SOURCE)/frameworks/av/include
+endif
+
+LOCAL_32_BIT_ONLY := true
+
+include $(BUILD_SHARED_LIBRARY)
+
+# -------------------------------------------------
+
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/../Android.common.mk
+
+LOCAL_SRC_FILES:= \
+	direct_media_test.cpp
+
+LOCAL_MODULE:= direct_media_test
+LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
+
+LOCAL_C_INCLUDES := \
+	$(HYBRIS_PATH)/include \
+	bionic \
+	bionic/libstdc++/include \
+	external/gtest/include \
+	external/stlport/stlport \
+	external/skia/include/core \
+	frameworks/base/include
+
+LOCAL_SHARED_LIBRARIES := \
+	libis_compat_layer \
+	libsf_compat_layer \
+	libmedia_compat_layer \
+	libcutils \
+	libutils \
+	libbinder \
+	libhardware \
+	libui \
+	libgui \
+	libEGL \
+	libGLESv2
+
+LOCAL_32_BIT_ONLY := true
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/../Android.common.mk
+
+LOCAL_CFLAGS += -Wno-multichar -D SIMPLE_PLAYER -std=gnu++0x
+
+LOCAL_SRC_FILES:= \
+	media_codec_layer.cpp \
+	media_codec_list.cpp \
+	media_format_layer.cpp \
+	codec.cpp \
+	SimplePlayer.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libstagefright \
+	libstagefright_foundation \
+	liblog \
+	libutils \
+	libbinder \
+	libmedia \
+	libgui \
+	libcutils \
+	libui
+
+LOCAL_C_INCLUDES:= \
+	$(HYBRIS_PATH)/include \
+	frameworks/av/media/libstagefright \
+	frameworks/native/include/media/openmax \
+	frameworks/base/media/libstagefright/include \
+	frameworks/base/include/media/stagefright \
+	frameworks/base/include/media
+
+LOCAL_MODULE:= codec
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_32_BIT_ONLY := true
+
+include $(BUILD_EXECUTABLE)
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/SimplePlayer.cpp
@@ -0,0 +1,777 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SimplePlayer"
+#include <utils/Log.h>
+
+#include "SimplePlayer.h"
+
+#include <gui/Surface.h>
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+#include <gui/SurfaceTextureClient.h>
+#endif
+#include <media/AudioTrack.h>
+#include <media/ICrypto.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/NativeWindowWrapper.h>
+#include <media/stagefright/NuMediaExtractor.h>
+
+#define USE_MEDIA_CODEC_LAYER
+
+namespace android {
+
+SimplePlayer::SimplePlayer()
+    : mState(UNINITIALIZED),
+      mDoMoreStuffGeneration(0),
+      mStartTimeRealUs(-1ll) {
+}
+
+SimplePlayer::~SimplePlayer() {
+}
+
+// static
+status_t PostAndAwaitResponse(
+        const sp<AMessage> &msg, sp<AMessage> *response) {
+    status_t err = msg->postAndAwaitResponse(response);
+    printf("%s\n", __PRETTY_FUNCTION__);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (!(*response)->findInt32("err", &err)) {
+        err = OK;
+    }
+
+    return err;
+}
+status_t SimplePlayer::setDataSource(const char *path) {
+    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
+    msg->setString("path", path);
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
+
+status_t SimplePlayer::setSurface(const sp<ISurfaceTexture> &surfaceTexture) {
+    sp<AMessage> msg = new AMessage(kWhatSetSurface, id());
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    sp<SurfaceTextureClient> surfaceTextureClient;
+    if (surfaceTexture != NULL) {
+        surfaceTextureClient = new SurfaceTextureClient(surfaceTexture);
+    }
+#else
+    sp<Surface> surfaceTextureClient;
+    if (surfaceTexture != NULL) {
+        surfaceTextureClient = new Surface(surfaceTexture);
+    }
+#endif
+
+    msg->setObject(
+            "native-window", new NativeWindowWrapper(surfaceTextureClient));
+
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
+
+status_t SimplePlayer::prepare() {
+    sp<AMessage> msg = new AMessage(kWhatPrepare, id());
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
+
+status_t SimplePlayer::start() {
+    printf("%s\n", __PRETTY_FUNCTION__);
+    sp<AMessage> msg = new AMessage(kWhatStart, id());
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
+
+status_t SimplePlayer::stop() {
+    sp<AMessage> msg = new AMessage(kWhatStop, id());
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
+
+status_t SimplePlayer::reset() {
+    sp<AMessage> msg = new AMessage(kWhatReset, id());
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
+
+void SimplePlayer::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatSetDataSource:
+        {
+            status_t err;
+            if (mState != UNINITIALIZED) {
+                err = INVALID_OPERATION;
+            } else {
+                CHECK(msg->findString("path", &mPath));
+                mState = UNPREPARED;
+            }
+
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
+        case kWhatSetSurface:
+        {
+            status_t err;
+            if (mState != UNPREPARED) {
+                err = INVALID_OPERATION;
+            } else {
+                sp<RefBase> obj;
+                CHECK(msg->findObject("native-window", &obj));
+
+                mNativeWindow = static_cast<NativeWindowWrapper *>(obj.get());
+
+                err = OK;
+            }
+
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
+        case kWhatPrepare:
+        {
+            status_t err;
+            if (mState != UNPREPARED) {
+                err = INVALID_OPERATION;
+            } else {
+                err = onPrepare();
+
+                if (err == OK) {
+                    mState = STOPPED;
+                }
+            }
+
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
+        case kWhatStart:
+        {
+            status_t err = OK;
+
+            if (mState == UNPREPARED) {
+                err = onPrepare();
+
+                if (err == OK) {
+                    mState = STOPPED;
+                }
+            }
+
+            if (err == OK) {
+                if (mState != STOPPED) {
+                    err = INVALID_OPERATION;
+                } else {
+                    err = onStart();
+
+                    if (err == OK) {
+                        mState = STARTED;
+                    }
+                }
+            }
+
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
+        case kWhatStop:
+        {
+            status_t err;
+
+            if (mState != STARTED) {
+                err = INVALID_OPERATION;
+            } else {
+                err = onStop();
+
+                if (err == OK) {
+                    mState = STOPPED;
+                }
+            }
+
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
+        case kWhatReset:
+        {
+            status_t err = OK;
+
+            if (mState == STARTED) {
+                CHECK_EQ(onStop(), (status_t)OK);
+                mState = STOPPED;
+            }
+
+            if (mState == STOPPED) {
+                err = onReset();
+                mState = UNINITIALIZED;
+            }
+
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
+        case kWhatDoMoreStuff:
+        {
+            int32_t generation;
+            CHECK(msg->findInt32("generation", &generation));
+
+            if (generation != mDoMoreStuffGeneration) {
+                break;
+            }
+
+            status_t err = onDoMoreStuff();
+
+            if (err == OK) {
+                msg->post(10000ll);
+            }
+            break;
+        }
+
+        default:
+            TRESPASS();
+    }
+}
+
+status_t SimplePlayer::onPrepare() {
+    CHECK_EQ(mState, UNPREPARED);
+    printf("%s\n", __PRETTY_FUNCTION__);
+
+    mExtractor = new NuMediaExtractor;
+
+    status_t err = mExtractor->setDataSource(mPath.c_str());
+
+    if (err != OK) {
+        mExtractor.clear();
+        return err;
+    }
+
+    if (mCodecLooper == NULL) {
+        mCodecLooper = new ALooper;
+        mCodecLooper->start();
+    }
+
+    bool haveAudio = false;
+    bool haveVideo = false;
+    for (size_t i = 0; i < mExtractor->countTracks(); ++i) {
+        sp<AMessage> format;
+        status_t err = mExtractor->getTrackFormat(i, &format);
+        CHECK_EQ(err, (status_t)OK);
+
+        AString mime;
+        int32_t width = 0, height = 0, maxInputSize = 0;
+        int64_t durationUs = 0;
+        sp<ABuffer> csd0, csd1;
+#ifdef USE_MEDIA_CODEC_LAYER
+        MediaFormat mformat;
+#endif
+        CHECK(format->findString("mime", &mime));
+
+        if (!haveAudio && !strncasecmp(mime.c_str(), "audio/", 6)) {
+            //haveAudio = true;
+            printf("*** Have audio but skipping it!\n");
+            continue;
+        } else if (!haveVideo && !strncasecmp(mime.c_str(), "video/", 6)) {
+            haveVideo = true;
+            CHECK(format->findInt32("width", &width));
+            CHECK(format->findInt32("height", &height));
+            CHECK(format->findInt64("durationUs", &durationUs));
+            CHECK(format->findInt32("max-input-size", &maxInputSize));
+            CHECK(format->findBuffer("csd-0", &csd0));
+            CHECK(format->findBuffer("csd-1", &csd1));
+#ifdef USE_MEDIA_CODEC_LAYER
+            mformat = media_format_create_video_format(mime.c_str(), width, height, durationUs, maxInputSize);
+            media_format_set_byte_buffer(mformat, "csd-0", csd0->data(), csd0->size());
+            media_format_set_byte_buffer(mformat, "csd-1", csd1->data(), csd1->size());
+#endif
+        } else {
+            continue;
+        }
+
+        err = mExtractor->selectTrack(i);
+        CHECK_EQ(err, (status_t)OK);
+
+        CodecState *state =
+            &mStateByTrackIndex.editValueAt(
+                    mStateByTrackIndex.add(i, CodecState()));
+
+        state->mNumFramesWritten = 0;
+#ifdef USE_MEDIA_CODEC_LAYER
+        state->mCodecDelegate = media_codec_create_by_codec_type(mime.c_str());
+        state->mCodec = media_codec_get(state->mCodecDelegate);
+        CHECK(state->mCodecDelegate != NULL);
+#else
+        state->mCodec = MediaCodec::CreateByType(
+                mCodecLooper, mime.c_str(), false /* encoder */);
+#endif
+
+        CHECK(state->mCodec != NULL);
+
+#ifdef USE_MEDIA_CODEC_LAYER
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+        err = media_codec_configure(state->mCodecDelegate, mformat, mNativeWindow->getSurfaceTextureClient().get(), 0);
+#else
+        err = media_codec_configure(state->mCodecDelegate, mformat, mNativeWindow->getSurface().get(), 0);
+#endif
+#else
+        err = state->mCodec->configure(
+                format,
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+                mNativeWindow->getSurfaceTextureClient(),
+#else
+                mNativeWindow->getSurface(),
+#endif
+                NULL /* crypto */,
+                0 /* flags */);
+#endif
+
+        CHECK_EQ(err, (status_t)OK);
+
+        size_t j = 0;
+        sp<ABuffer> buffer;
+        // Place the CSD data into the source buffer
+        while (format->findBuffer(StringPrintf("csd-%d", j).c_str(), &buffer)) {
+            state->mCSD.push_back(buffer);
+
+            ++j;
+        }
+    }
+
+    for (size_t i = 0; i < mStateByTrackIndex.size(); ++i) {
+        CodecState *state = &mStateByTrackIndex.editValueAt(i);
+
+#ifdef USE_MEDIA_CODEC_LAYER
+        status_t err = media_codec_start(state->mCodecDelegate);
+#else
+        status_t err = state->mCodec->start();
+#endif
+        CHECK_EQ(err, (status_t)OK);
+
+#ifdef USE_MEDIA_CODEC_LAYER
+        size_t nInputBuffers = media_codec_get_input_buffers_size(state->mCodecDelegate);
+        ALOGD("nInputBuffers: %u", nInputBuffers);
+        for (size_t i=0; i<nInputBuffers; i++)
+        {
+            uint8_t *data = media_codec_get_nth_input_buffer(state->mCodecDelegate, i);
+            CHECK(data != NULL);
+            size_t size = media_codec_get_nth_input_buffer_capacity(state->mCodecDelegate, i);
+            ALOGD("input buffer[%d] size: %d", i, size);
+            sp<ABuffer> buf = new ABuffer(data, size);
+            state->mBuffers[0].insertAt(new ABuffer(data, size), i);
+        }
+#else
+        err = state->mCodec->getInputBuffers(&state->mBuffers[0]);
+        CHECK_EQ(err, (status_t)OK);
+#endif
+
+        err = state->mCodec->getOutputBuffers(&state->mBuffers[1]);
+        CHECK_EQ(err, (status_t)OK);
+
+        for (size_t j = 0; j < state->mCSD.size(); ++j) {
+            const sp<ABuffer> &srcBuffer = state->mCSD.itemAt(j);
+
+            size_t index;
+#ifdef USE_MEDIA_CODEC_LAYER
+            err = media_codec_dequeue_input_buffer(state->mCodecDelegate, &index, -1ll);
+#else
+            err = state->mCodec->dequeueInputBuffer(&index, -1ll);
+#endif
+            CHECK_EQ(err, (status_t)OK);
+
+            const sp<ABuffer> &dstBuffer = state->mBuffers[0].itemAt(index);
+
+            CHECK_LE(srcBuffer->size(), dstBuffer->capacity());
+            dstBuffer->setRange(0, srcBuffer->size());
+            memcpy(dstBuffer->data(), srcBuffer->data(), srcBuffer->size());
+
+#ifdef USE_MEDIA_CODEC_LAYER
+            MediaCodecBufferInfo bufInfo;
+            bufInfo.index = index;
+            bufInfo.offset = 0;
+            bufInfo.size = dstBuffer->size();
+            bufInfo.presentation_time_us = 0ll;
+            bufInfo.flags = MediaCodec::BUFFER_FLAG_CODECCONFIG;
+
+            err = media_codec_queue_input_buffer(
+                    state->mCodecDelegate,
+                    &bufInfo);
+
+#else
+            err = state->mCodec->queueInputBuffer(
+                    index,
+                    0,
+                    dstBuffer->size(),
+                    0ll,
+                    MediaCodec::BUFFER_FLAG_CODECCONFIG);
+#endif
+            CHECK_EQ(err, (status_t)OK);
+        }
+    }
+
+    return OK;
+}
+
+status_t SimplePlayer::onStart() {
+    CHECK_EQ(mState, STOPPED);
+
+    mStartTimeRealUs = -1ll;
+
+    sp<AMessage> msg = new AMessage(kWhatDoMoreStuff, id());
+    msg->setInt32("generation", ++mDoMoreStuffGeneration);
+    msg->post();
+
+    return OK;
+}
+
+status_t SimplePlayer::onStop() {
+    CHECK_EQ(mState, STARTED);
+
+    ++mDoMoreStuffGeneration;
+
+    return OK;
+}
+
+status_t SimplePlayer::onReset() {
+    CHECK_EQ(mState, STOPPED);
+
+    for (size_t i = 0; i < mStateByTrackIndex.size(); ++i) {
+        CodecState *state = &mStateByTrackIndex.editValueAt(i);
+
+        CHECK_EQ(state->mCodec->release(), (status_t)OK);
+    }
+
+    mStartTimeRealUs = -1ll;
+
+    mStateByTrackIndex.clear();
+    mCodecLooper.clear();
+    mExtractor.clear();
+    mNativeWindow.clear();
+    mPath.clear();
+
+    return OK;
+}
+
+status_t SimplePlayer::onDoMoreStuff() {
+    ALOGV("onDoMoreStuff");
+    for (size_t i = 0; i < mStateByTrackIndex.size(); ++i) {
+        CodecState *state = &mStateByTrackIndex.editValueAt(i);
+
+        status_t err;
+        do {
+            size_t index;
+#ifdef USE_MEDIA_CODEC_LAYER
+            err = media_codec_dequeue_input_buffer(state->mCodecDelegate, &index, 0ll);
+#else
+            err = state->mCodec->dequeueInputBuffer(&index);
+#endif
+
+            if (err == OK) {
+                ALOGD("dequeued input buffer on track %d",
+                      mStateByTrackIndex.keyAt(i));
+
+                state->mAvailInputBufferIndices.push_back(index);
+            } else {
+                ALOGD("dequeueInputBuffer on track %d returned %d",
+                      mStateByTrackIndex.keyAt(i), err);
+            }
+        } while (err == OK);
+
+        do {
+#ifdef USE_MEDIA_CODEC_LAYER
+            BufferInfo info;
+            MediaCodecBufferInfo bufInfo;
+            err = media_codec_dequeue_output_buffer(
+                    state->mCodecDelegate,
+                    &bufInfo,
+                    0ll);
+
+            info.mIndex = bufInfo.index;
+            info.mOffset = bufInfo.offset;
+            info.mSize = bufInfo.size;
+            info.mPresentationTimeUs = bufInfo.presentation_time_us;
+            info.mFlags = bufInfo.flags;
+
+#else
+            BufferInfo info;
+            err = state->mCodec->dequeueOutputBuffer(
+                    &info.mIndex,
+                    &info.mOffset,
+                    &info.mSize,
+                    &info.mPresentationTimeUs,
+                    &info.mFlags);
+#endif
+
+            if (err == OK) {
+                ALOGV("dequeued output buffer on track %d",
+                      mStateByTrackIndex.keyAt(i));
+
+                state->mAvailOutputBufferInfos.push_back(info);
+            } else if (err == INFO_FORMAT_CHANGED) {
+                err = onOutputFormatChanged(mStateByTrackIndex.keyAt(i), state);
+                CHECK_EQ(err, (status_t)OK);
+            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
+                err = state->mCodec->getOutputBuffers(&state->mBuffers[1]);
+                CHECK_EQ(err, (status_t)OK);
+            } else {
+                ALOGV("dequeueOutputBuffer on track %d returned %d",
+                      mStateByTrackIndex.keyAt(i), err);
+            }
+        } while (err == OK
+                || err == INFO_FORMAT_CHANGED
+                || err == INFO_OUTPUT_BUFFERS_CHANGED);
+    }
+
+    for (;;) {
+        size_t trackIndex;
+        status_t err = mExtractor->getSampleTrackIndex(&trackIndex);
+
+        if (err != OK) {
+            ALOGI("encountered input EOS.");
+            break;
+        } else {
+            CodecState *state = &mStateByTrackIndex.editValueFor(trackIndex);
+
+            if (state->mAvailInputBufferIndices.empty()) {
+                break;
+            }
+
+            size_t index = *state->mAvailInputBufferIndices.begin();
+            state->mAvailInputBufferIndices.erase(
+                    state->mAvailInputBufferIndices.begin());
+
+            const sp<ABuffer> &dstBuffer =
+                state->mBuffers[0].itemAt(index);
+
+            err = mExtractor->readSampleData(dstBuffer);
+            CHECK_EQ(err, (status_t)OK);
+
+            int64_t timeUs;
+            CHECK_EQ(mExtractor->getSampleTime(&timeUs), (status_t)OK);
+
+#ifdef USE_MEDIA_CODEC_LAYER
+            MediaCodecBufferInfo bufInfo;
+            bufInfo.index = index;
+            bufInfo.offset = dstBuffer->offset();
+            bufInfo.size = dstBuffer->size();
+            bufInfo.presentation_time_us = timeUs;
+            bufInfo.flags = 0;
+
+            err = media_codec_queue_input_buffer(
+                    state->mCodecDelegate,
+                    &bufInfo);
+
+#else
+            err = state->mCodec->queueInputBuffer(
+                    index,
+                    dstBuffer->offset(),
+                    dstBuffer->size(),
+                    timeUs,
+                    0);
+#endif
+            CHECK_EQ(err, (status_t)OK);
+
+            ALOGV("enqueued input data on track %d", trackIndex);
+
+            err = mExtractor->advance();
+            CHECK_EQ(err, (status_t)OK);
+        }
+    }
+
+    int64_t nowUs = ALooper::GetNowUs();
+
+    if (mStartTimeRealUs < 0ll) {
+        mStartTimeRealUs = nowUs + 1000000ll;
+    }
+
+    for (size_t i = 0; i < mStateByTrackIndex.size(); ++i) {
+        CodecState *state = &mStateByTrackIndex.editValueAt(i);
+
+        while (!state->mAvailOutputBufferInfos.empty()) {
+            BufferInfo *info = &*state->mAvailOutputBufferInfos.begin();
+
+            int64_t whenRealUs = info->mPresentationTimeUs + mStartTimeRealUs;
+            int64_t lateByUs = nowUs - whenRealUs;
+
+            if (lateByUs > -10000ll) {
+                bool release = true;
+
+                if (lateByUs > 30000ll) {
+                    ALOGI("track %d buffer late by %lld us, dropping.",
+                          mStateByTrackIndex.keyAt(i), lateByUs);
+                    state->mCodec->releaseOutputBuffer(info->mIndex);
+                } else {
+                    if (state->mAudioTrack != NULL) {
+                        const sp<ABuffer> &srcBuffer =
+                            state->mBuffers[1].itemAt(info->mIndex);
+
+                        renderAudio(state, info, srcBuffer);
+
+                        if (info->mSize > 0) {
+                            release = false;
+                        }
+                    }
+
+                    if (release) {
+#ifdef USE_MEDIA_CODEC_LAYER
+                        ALOGD("Rendering output buffer index %d and releasing", info->mIndex);
+                        state->mCodec->renderOutputBufferAndRelease(
+                                info->mIndex);
+#else
+                        ALOGD("Releasing output buffer index %d", info->mIndex);
+                        state->mCodec->releaseOutputBuffer(info->mIndex);
+#endif
+                    }
+                }
+
+                if (release) {
+                    state->mAvailOutputBufferInfos.erase(
+                            state->mAvailOutputBufferInfos.begin());
+
+                    info = NULL;
+                } else {
+                    break;
+                }
+            } else {
+                ALOGV("track %d buffer early by %lld us.",
+                      mStateByTrackIndex.keyAt(i), -lateByUs);
+                break;
+            }
+        }
+    }
+
+    return OK;
+}
+
+status_t SimplePlayer::onOutputFormatChanged(
+        size_t trackIndex, CodecState *state) {
+    sp<AMessage> format;
+    status_t err = state->mCodec->getOutputFormat(&format);
+
+    if (err != OK) {
+        return err;
+    }
+
+    AString mime;
+    CHECK(format->findString("mime", &mime));
+
+    if (!strncasecmp(mime.c_str(), "audio/", 6)) {
+        int32_t channelCount;
+        int32_t sampleRate;
+        CHECK(format->findInt32("channel-count", &channelCount));
+        CHECK(format->findInt32("sample-rate", &sampleRate));
+
+        state->mAudioTrack = new AudioTrack(
+                AUDIO_STREAM_MUSIC,
+                sampleRate,
+                AUDIO_FORMAT_PCM_16_BIT,
+                audio_channel_out_mask_from_count(channelCount),
+                0);
+
+        state->mNumFramesWritten = 0;
+    }
+
+    return OK;
+}
+
+void SimplePlayer::renderAudio(
+        CodecState *state, BufferInfo *info, const sp<ABuffer> &buffer) {
+    CHECK(state->mAudioTrack != NULL);
+
+    if (state->mAudioTrack->stopped()) {
+        state->mAudioTrack->start();
+    }
+
+    uint32_t numFramesPlayed;
+    CHECK_EQ(state->mAudioTrack->getPosition(&numFramesPlayed), (status_t)OK);
+
+    uint32_t numFramesAvailableToWrite =
+        state->mAudioTrack->frameCount()
+            - (state->mNumFramesWritten - numFramesPlayed);
+
+    size_t numBytesAvailableToWrite =
+        numFramesAvailableToWrite * state->mAudioTrack->frameSize();
+
+    size_t copy = info->mSize;
+    if (copy > numBytesAvailableToWrite) {
+        copy = numBytesAvailableToWrite;
+    }
+
+    if (copy == 0) {
+        return;
+    }
+
+    int64_t startTimeUs = ALooper::GetNowUs();
+
+    ssize_t nbytes = state->mAudioTrack->write(
+            buffer->base() + info->mOffset, copy);
+
+    CHECK_EQ(nbytes, (ssize_t)copy);
+
+    int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
+
+    uint32_t numFramesWritten = nbytes / state->mAudioTrack->frameSize();
+
+    if (delayUs > 2000ll) {
+        ALOGW("AudioTrack::write took %lld us, numFramesAvailableToWrite=%u, "
+              "numFramesWritten=%u",
+              delayUs, numFramesAvailableToWrite, numFramesWritten);
+    }
+
+    info->mOffset += nbytes;
+    info->mSize -= nbytes;
+
+    state->mNumFramesWritten += numFramesWritten;
+}
+
+}  // namespace android
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/SimplePlayer.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AString.h>
+#include <utils/KeyedVector.h>
+
+#include <hybris/media/media_codec_layer.h>
+
+namespace android {
+
+struct ABuffer;
+struct ALooper;
+struct AudioTrack;
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+struct ISurfaceTexture;
+#else
+struct IGraphicBufferProducer;
+#endif
+struct MediaCodec;
+struct NativeWindowWrapper;
+struct NuMediaExtractor;
+
+struct SimplePlayer : public AHandler {
+    SimplePlayer();
+
+    status_t setDataSource(const char *path);
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    status_t setSurface(const sp<ISurfaceTexture> &surfaceTexture);
+#else
+    status_t setSurface(const sp<IGraphicBufferProducer> &surfaceTexture);
+#endif
+    status_t prepare();
+    status_t start();
+    status_t stop();
+    status_t reset();
+
+protected:
+    virtual ~SimplePlayer();
+
+    virtual void onMessageReceived(const sp<AMessage> &msg);
+
+private:
+    enum State {
+        UNINITIALIZED,
+        UNPREPARED,
+        STOPPED,
+        STARTED
+    };
+
+    enum {
+        kWhatSetDataSource,
+        kWhatSetSurface,
+        kWhatPrepare,
+        kWhatStart,
+        kWhatStop,
+        kWhatReset,
+        kWhatDoMoreStuff,
+    };
+
+    struct BufferInfo {
+        size_t mIndex;
+        size_t mOffset;
+        size_t mSize;
+        int64_t mPresentationTimeUs;
+        uint32_t mFlags;
+    };
+
+    struct CodecState
+    {
+        sp<MediaCodec> mCodec;
+        MediaCodecDelegate mCodecDelegate;
+        Vector<sp<ABuffer> > mCSD;
+        Vector<sp<ABuffer> > mBuffers[2];
+
+        List<size_t> mAvailInputBufferIndices;
+        List<BufferInfo> mAvailOutputBufferInfos;
+
+        sp<AudioTrack> mAudioTrack;
+        uint32_t mNumFramesWritten;
+    };
+
+    State mState;
+    AString mPath;
+    sp<NativeWindowWrapper> mNativeWindow;
+
+    sp<NuMediaExtractor> mExtractor;
+    sp<ALooper> mCodecLooper;
+    KeyedVector<size_t, CodecState> mStateByTrackIndex;
+    int32_t mDoMoreStuffGeneration;
+
+    int64_t mStartTimeRealUs;
+
+    status_t onPrepare();
+    status_t onStart();
+    status_t onStop();
+    status_t onReset();
+    status_t onDoMoreStuff();
+    status_t onOutputFormatChanged(size_t trackIndex, CodecState *state);
+
+    void renderAudio(
+            CodecState *state, BufferInfo *info, const sp<ABuffer> &buffer);
+
+    DISALLOW_EVIL_CONSTRUCTORS(SimplePlayer);
+};
+
+}  // namespace android
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/camera_service.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "CameraServiceCompatLayer"
+
+#include "media_recorder_factory.h"
+#include "media_recorder.h"
+
+#include <media/camera_record_service.h>
+#include <CameraService.h>
+
+#include <signal.h>
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__)
+
+using namespace android;
+
+/*!
+ * \brief main() instantiates the MediaRecorderFactory Binder server and the CameraService
+ */
+int main(int argc, char** argv)
+{
+    signal(SIGPIPE, SIG_IGN);
+
+    ALOGV("Starting camera services (MediaRecorderFactory, CameraRecordService & CameraService)");
+
+    // Instantiate the in-process MediaRecorderFactory which is responsible
+    // for creating a new IMediaRecorder (MediaRecorder) instance over Binder
+    MediaRecorderFactory::instantiate();
+    // Enable audio recording for camera recording
+    CameraRecordService::instantiate();
+    CameraService::instantiate();
+    ProcessState::self()->startThreadPool();
+    IPCThreadState::self()->joinThreadPool();
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/codec.cpp
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "codec"
+#include <utils/Log.h>
+
+#include "SimplePlayer.h"
+
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <media/ICrypto.h>
+#include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/NuMediaExtractor.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayInfo.h>
+
+static void usage(const char *me) {
+    fprintf(stderr, "usage: %s [-a] use audio\n"
+                    "\t\t[-v] use video\n"
+                    "\t\t[-p] playback\n"
+                    "\t\t[-S] allocate buffers from a surface\n",
+                    me);
+
+    exit(1);
+}
+
+namespace android {
+
+struct CodecState {
+    sp<MediaCodec> mCodec;
+    Vector<sp<ABuffer> > mInBuffers;
+    Vector<sp<ABuffer> > mOutBuffers;
+    bool mSignalledInputEOS;
+    bool mSawOutputEOS;
+    int64_t mNumBuffersDecoded;
+    int64_t mNumBytesDecoded;
+    bool mIsAudio;
+};
+
+}  // namespace android
+
+static int decode(
+        const android::sp<android::ALooper> &looper,
+        const char *path,
+        bool useAudio,
+        bool useVideo,
+        const android::sp<android::Surface> &surface) {
+    using namespace android;
+
+    static int64_t kTimeout = 500ll;
+
+    sp<NuMediaExtractor> extractor = new NuMediaExtractor;
+    if (extractor->setDataSource(path) != OK) {
+        fprintf(stderr, "unable to instantiate extractor.\n");
+        return 1;
+    }
+
+    KeyedVector<size_t, CodecState> stateByTrack;
+
+    bool haveAudio = false;
+    bool haveVideo = false;
+    for (size_t i = 0; i < extractor->countTracks(); ++i) {
+        sp<AMessage> format;
+        status_t err = extractor->getTrackFormat(i, &format);
+        CHECK_EQ(err, (status_t)OK);
+
+        AString mime;
+        CHECK(format->findString("mime", &mime));
+
+        bool isAudio = !strncasecmp(mime.c_str(), "audio/", 6);
+        bool isVideo = !strncasecmp(mime.c_str(), "video/", 6);
+
+        if (useAudio && !haveAudio && isAudio) {
+            haveAudio = true;
+        } else if (useVideo && !haveVideo && isVideo) {
+            haveVideo = true;
+        } else {
+            continue;
+        }
+
+        ALOGV("selecting track %d", i);
+
+        err = extractor->selectTrack(i);
+        CHECK_EQ(err, (status_t)OK);
+
+        CodecState *state =
+            &stateByTrack.editValueAt(stateByTrack.add(i, CodecState()));
+
+        state->mNumBytesDecoded = 0;
+        state->mNumBuffersDecoded = 0;
+        state->mIsAudio = isAudio;
+
+        state->mCodec = MediaCodec::CreateByType(
+                looper, mime.c_str(), false /* encoder */);
+
+        CHECK(state->mCodec != NULL);
+
+        err = state->mCodec->configure(
+                format, isVideo ? surface : NULL,
+                NULL /* crypto */,
+                0 /* flags */);
+
+        CHECK_EQ(err, (status_t)OK);
+
+        state->mSignalledInputEOS = false;
+        state->mSawOutputEOS = false;
+    }
+
+    CHECK(!stateByTrack.isEmpty());
+
+    int64_t startTimeUs = ALooper::GetNowUs();
+
+    for (size_t i = 0; i < stateByTrack.size(); ++i) {
+        CodecState *state = &stateByTrack.editValueAt(i);
+
+        sp<MediaCodec> codec = state->mCodec;
+
+        CHECK_EQ((status_t)OK, codec->start());
+
+        CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers));
+        CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers));
+
+        ALOGV("got %d input and %d output buffers",
+              state->mInBuffers.size(), state->mOutBuffers.size());
+    }
+
+    bool sawInputEOS = false;
+
+    for (;;) {
+        if (!sawInputEOS) {
+            size_t trackIndex;
+            status_t err = extractor->getSampleTrackIndex(&trackIndex);
+
+            if (err != OK) {
+                ALOGV("saw input eos");
+                sawInputEOS = true;
+            } else {
+                CodecState *state = &stateByTrack.editValueFor(trackIndex);
+
+                size_t index;
+                err = state->mCodec->dequeueInputBuffer(&index, kTimeout);
+
+                if (err == OK) {
+                    ALOGV("filling input buffer %d", index);
+
+                    const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index);
+
+                    err = extractor->readSampleData(buffer);
+                    CHECK_EQ(err, (status_t)OK);
+
+                    int64_t timeUs;
+                    err = extractor->getSampleTime(&timeUs);
+                    CHECK_EQ(err, (status_t)OK);
+
+                    uint32_t bufferFlags = 0;
+
+                    err = state->mCodec->queueInputBuffer(
+                            index,
+                            0 /* offset */,
+                            buffer->size(),
+                            timeUs,
+                            bufferFlags);
+
+                    CHECK_EQ(err, (status_t)OK);
+
+                    extractor->advance();
+                } else {
+                    CHECK_EQ(err, -EAGAIN);
+                }
+            }
+        } else {
+            for (size_t i = 0; i < stateByTrack.size(); ++i) {
+                CodecState *state = &stateByTrack.editValueAt(i);
+
+                if (!state->mSignalledInputEOS) {
+                    size_t index;
+                    status_t err =
+                        state->mCodec->dequeueInputBuffer(&index, kTimeout);
+
+                    if (err == OK) {
+                        ALOGV("signalling input EOS on track %d", i);
+
+                        err = state->mCodec->queueInputBuffer(
+                                index,
+                                0 /* offset */,
+                                0 /* size */,
+                                0ll /* timeUs */,
+                                MediaCodec::BUFFER_FLAG_EOS);
+
+                        CHECK_EQ(err, (status_t)OK);
+
+                        state->mSignalledInputEOS = true;
+                    } else {
+                        CHECK_EQ(err, -EAGAIN);
+                    }
+                }
+            }
+        }
+
+        bool sawOutputEOSOnAllTracks = true;
+        for (size_t i = 0; i < stateByTrack.size(); ++i) {
+            CodecState *state = &stateByTrack.editValueAt(i);
+            if (!state->mSawOutputEOS) {
+                sawOutputEOSOnAllTracks = false;
+                break;
+            }
+        }
+
+        if (sawOutputEOSOnAllTracks) {
+            break;
+        }
+
+        for (size_t i = 0; i < stateByTrack.size(); ++i) {
+            CodecState *state = &stateByTrack.editValueAt(i);
+
+            if (state->mSawOutputEOS) {
+                continue;
+            }
+
+            size_t index;
+            size_t offset;
+            size_t size;
+            int64_t presentationTimeUs;
+            uint32_t flags;
+            status_t err = state->mCodec->dequeueOutputBuffer(
+                    &index, &offset, &size, &presentationTimeUs, &flags,
+                    kTimeout);
+
+            if (err == OK) {
+                ALOGV("draining output buffer %d, time = %lld us",
+                      index, presentationTimeUs);
+
+                ++state->mNumBuffersDecoded;
+                state->mNumBytesDecoded += size;
+
+                err = state->mCodec->releaseOutputBuffer(index);
+                CHECK_EQ(err, (status_t)OK);
+
+                if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+                    ALOGV("reached EOS on output.");
+
+                    state->mSawOutputEOS = true;
+                }
+            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
+                ALOGV("INFO_OUTPUT_BUFFERS_CHANGED");
+                CHECK_EQ((status_t)OK,
+                         state->mCodec->getOutputBuffers(&state->mOutBuffers));
+
+                ALOGV("got %d output buffers", state->mOutBuffers.size());
+            } else if (err == INFO_FORMAT_CHANGED) {
+                sp<AMessage> format;
+                CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format));
+
+                ALOGV("INFO_FORMAT_CHANGED: %s", format->debugString().c_str());
+            } else {
+                CHECK_EQ(err, -EAGAIN);
+            }
+        }
+    }
+
+    int64_t elapsedTimeUs = ALooper::GetNowUs() - startTimeUs;
+
+    for (size_t i = 0; i < stateByTrack.size(); ++i) {
+        CodecState *state = &stateByTrack.editValueAt(i);
+
+        CHECK_EQ((status_t)OK, state->mCodec->release());
+
+        if (state->mIsAudio) {
+            ALOGD("track %d: %lld bytes received. %.2f KB/sec\n",
+                   i,
+                   state->mNumBytesDecoded,
+                   state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs);
+        } else {
+            ALOGD("track %d: %lld frames decoded, %.2f fps. %lld bytes "
+                   "received. %.2f KB/sec\n",
+                   i,
+                   state->mNumBuffersDecoded,
+                   state->mNumBuffersDecoded * 1E6 / elapsedTimeUs,
+                   state->mNumBytesDecoded,
+                   state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs);
+        }
+    }
+
+    return 0;
+}
+
+int main(int argc, char **argv) {
+    using namespace android;
+
+    const char *me = argv[0];
+
+    bool useAudio = false;
+    bool useVideo = false;
+    bool playback = false;
+    bool useSurface = false;
+
+    int res;
+    while ((res = getopt(argc, argv, "havpSD")) >= 0) {
+        switch (res) {
+            case 'a':
+            {
+                useAudio = true;
+                break;
+            }
+
+            case 'v':
+            {
+                useVideo = true;
+                break;
+            }
+
+            case 'p':
+            {
+                playback = true;
+                break;
+            }
+
+            case 'S':
+            {
+                useSurface = true;
+                break;
+            }
+
+            case '?':
+            case 'h':
+            default:
+            {
+                usage(me);
+            }
+        }
+    }
+
+    argc -= optind;
+    argv += optind;
+
+    if (argc != 1) {
+        usage(me);
+    }
+
+    if (!useAudio && !useVideo) {
+        useAudio = useVideo = true;
+    }
+
+    ProcessState::self()->startThreadPool();
+
+    DataSource::RegisterDefaultSniffers();
+
+    sp<ALooper> looper = new ALooper;
+    looper->start();
+
+    sp<SurfaceComposerClient> composerClient;
+    sp<SurfaceControl> control;
+    sp<Surface> surface;
+
+    if (playback || (useSurface && useVideo)) {
+        composerClient = new SurfaceComposerClient;
+        CHECK_EQ(composerClient->initCheck(), (status_t)OK);
+
+        sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
+                ISurfaceComposer::eDisplayIdMain));
+        DisplayInfo info;
+        SurfaceComposerClient::getDisplayInfo(display, &info);
+        ssize_t displayWidth = info.w;
+        ssize_t displayHeight = info.h;
+
+        ALOGV("display is %ld x %ld\n", displayWidth, displayHeight);
+
+        control = composerClient->createSurface(
+                String8("A Surface"),
+                displayWidth,
+                displayHeight,
+                PIXEL_FORMAT_RGB_565,
+                0);
+
+        CHECK(control != NULL);
+        CHECK(control->isValid());
+
+        SurfaceComposerClient::openGlobalTransaction();
+        CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
+        CHECK_EQ(control->show(), (status_t)OK);
+        SurfaceComposerClient::closeGlobalTransaction();
+
+        surface = control->getSurface();
+        CHECK(surface != NULL);
+    }
+
+    if (playback) {
+        sp<SimplePlayer> player = new SimplePlayer;
+        looper->registerHandler(player);
+
+        player->setDataSource(argv[0]);
+        player->setSurface(surface->getSurfaceTexture());
+        player->start();
+        ALOGD("Playing for 60 seconds\n");
+        sleep(60);
+        player->stop();
+        player->reset();
+    } else {
+        decode(looper, argv[0], useAudio, useVideo, surface);
+    }
+
+    if (playback || (useSurface && useVideo)) {
+        composerClient->dispose();
+    }
+
+    looper->stop();
+
+    return 0;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/decoding_service.cpp
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+// Uncomment to enable verbose debug output
+#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "DecodingService"
+
+#include "decoding_service_priv.h"
+
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/BpBinder.h>
+
+typedef void* EGLDisplay;
+typedef void* EGLSyncKHR;
+
+#include <ui/GraphicBuffer.h>
+#include <gui/GraphicBufferAlloc.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/Surface.h>
+#include <gui/NativeBufferAlloc.h>
+
+namespace android {
+
+IMPLEMENT_META_INTERFACE(DecodingService, "android.media.IDecodingService");
+IMPLEMENT_META_INTERFACE(DecodingServiceSession, "android.media.IDecodingServiceSession");
+
+enum {
+    GET_IGRAPHICBUFFERCONSUMER = IBinder::FIRST_CALL_TRANSACTION,
+    GET_IGRAPHICBUFFERPRODUCER,
+    REGISTER_SESSION,
+    UNREGISTER_SESSION,
+};
+
+// ----------------------------------------------------------------------
+
+status_t BnDecodingService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    switch (code) {
+        case GET_IGRAPHICBUFFERCONSUMER: {
+            CHECK_INTERFACE(IDecodingService, data, reply);
+            sp<IGraphicBufferConsumer> gbc;
+            status_t res = getIGraphicBufferConsumer(&gbc);
+
+            reply->writeStrongBinder(gbc->asBinder());
+            reply->writeInt32(res);
+
+            return NO_ERROR;
+        } break;
+        case GET_IGRAPHICBUFFERPRODUCER: {
+            CHECK_INTERFACE(IDecodingService, data, reply);
+            sp<IGraphicBufferProducer> gbp;
+            status_t res = getIGraphicBufferProducer(&gbp);
+
+            reply->writeStrongBinder(gbp->asBinder());
+            reply->writeInt32(res);
+
+            return NO_ERROR;
+        } break;
+        case REGISTER_SESSION: {
+            CHECK_INTERFACE(IDecodingService, data, reply);
+            sp<IBinder> binder = data.readStrongBinder();
+            uint32_t handle = data.readInt32();
+            sp<IDecodingServiceSession> session(new BpDecodingServiceSession(binder));
+            registerSession(session, handle);
+
+            return NO_ERROR;
+        } break;
+        case UNREGISTER_SESSION: {
+            CHECK_INTERFACE(IDecodingService, data, reply);
+            unregisterSession();
+
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+status_t BpDecodingService::getIGraphicBufferConsumer(sp<IGraphicBufferConsumer>* gbc)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    Parcel data, reply;
+    data.writeInterfaceToken(IDecodingService::getInterfaceDescriptor());
+    remote()->transact(GET_IGRAPHICBUFFERCONSUMER, data, &reply);
+    *gbc = interface_cast<IGraphicBufferConsumer>(reply.readStrongBinder());
+    return reply.readInt32();
+}
+
+status_t BpDecodingService::getIGraphicBufferProducer(sp<IGraphicBufferProducer>* gbp)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    Parcel data, reply;
+    data.writeInterfaceToken(IDecodingService::getInterfaceDescriptor());
+    remote()->transact(GET_IGRAPHICBUFFERPRODUCER, data, &reply);
+    *gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder());
+    return NO_ERROR;
+}
+
+status_t BpDecodingService::registerSession(const sp<IDecodingServiceSession>& session, uint32_t handle)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    Parcel data, reply;
+    data.writeInterfaceToken(IDecodingService::getInterfaceDescriptor());
+    data.writeStrongBinder(session->asBinder());
+    data.writeInt32(handle);
+    remote()->transact(REGISTER_SESSION, data, &reply);
+    return NO_ERROR;
+}
+
+status_t BpDecodingService::unregisterSession()
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    Parcel data, reply;
+    data.writeInterfaceToken(IDecodingService::getInterfaceDescriptor());
+    remote()->transact(UNREGISTER_SESSION, data, &reply);
+    return NO_ERROR;
+}
+
+sp<DecodingService> DecodingService::decoding_service = NULL;
+
+DecodingService::DecodingService()
+    : client_death_cb(NULL),
+      client_death_context(NULL)
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+}
+
+DecodingService::~DecodingService()
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+}
+
+void DecodingService::instantiate()
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    defaultServiceManager()->addService(
+            String16(IDecodingService::exported_service_name()), service_instance());
+    ALOGD("Added Binder service '%s' to ServiceManager", IDecodingService::exported_service_name());
+
+    service_instance()->createBufferQueue();
+}
+
+sp<DecodingService>& DecodingService::service_instance()
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+
+    // TODO Add a mutex here
+    if (decoding_service == NULL)
+    {
+        ALOGD("Creating new static instance of DecodingService");
+        decoding_service = new DecodingService();
+    }
+
+    return decoding_service;
+}
+
+void DecodingService::setDecodingClientDeathCb(DecodingClientDeathCbHybris cb, uint32_t handle, void* context)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+
+    ClientCb *holder = (ClientCb*) malloc(sizeof(ClientCb));
+    holder->cb = cb;
+    holder->context = context;
+
+    clients.add(handle, holder);
+}
+
+status_t DecodingService::getIGraphicBufferConsumer(sp<IGraphicBufferConsumer>* gbc)
+{
+    // TODO: Make sure instantiate() has been called first
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    ALOGD("Calling Pid: %d", pid);
+
+#if ANDROID_VERSION_MAJOR==5
+    *gbc = consumer;
+#else
+    *gbc = buffer_queue;
+#endif
+
+    return OK;
+}
+
+status_t DecodingService::getIGraphicBufferProducer(sp<IGraphicBufferProducer>* gbp)
+{
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    ALOGD("Calling Pid: %d", pid);
+
+#if ANDROID_VERSION_MAJOR==5
+    *gbp = producer;
+#else
+    *gbp = buffer_queue;
+#endif
+    ALOGD("producer(gbp): %p", (void*)gbp->get());
+    return OK;
+}
+
+status_t DecodingService::registerSession(const sp<IDecodingServiceSession>& session, uint32_t handle)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+
+    // Add session/handle to running clients map and connect death observer
+    status_t ret = session->asBinder()->linkToDeath(sp<IBinder::DeathRecipient>(this));
+    clientCbs.add(session->asBinder(), clients.valueFor(handle));
+    clients.removeItem(handle);
+
+    // Create a new BufferQueue instance so that the next created client plays
+    // video correctly
+    createBufferQueue();
+
+    return ret;
+}
+
+status_t DecodingService::unregisterSession()
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    if (session != NULL)
+    {
+        session->asBinder()->unlinkToDeath(this);
+        session.clear();
+        // Reset the BufferQueue instance so that the next created client plays
+        // video correctly
+#if ANDROID_VERSION_MAJOR==5
+        producer.clear();
+        consumer.clear();
+#else
+        buffer_queue.clear();
+#endif
+    }
+
+    return OK;
+}
+
+void DecodingService::createBufferQueue()
+{
+    // Use a new native buffer allocator vs the default one, which means it'll use the proper one
+    // that will allow rendering to work with Mir
+    sp<IGraphicBufferAlloc> g_buffer_alloc(new GraphicBufferAlloc());
+
+    // This BuferQueue is shared between the client and the service
+#if ANDROID_VERSION_MAJOR==5
+    BufferQueue::createBufferQueue(&producer, &consumer);
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
+    sp<NativeBufferAlloc> native_alloc(new NativeBufferAlloc());
+    buffer_queue = new BufferQueue(false, NULL, native_alloc);
+#else
+    buffer_queue = new BufferQueue(NULL);
+    ALOGD("buffer_queue: %p", (void*)buffer_queue.get());
+#endif
+#if ANDROID_VERSION_MAJOR==5
+    producer->setBufferCount(5);
+#else
+    buffer_queue->setBufferCount(5);
+#endif
+}
+
+void DecodingService::binderDied(const wp<IBinder>& who)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+
+    sp<IBinder> sp = who.promote();
+    ClientCb *cb = clientCbs.valueFor(sp);
+
+    if (cb && cb->cb != NULL) {
+        cb->cb(cb->context);
+        free(cb);
+        clientCbs.removeItem(sp);
+    }
+
+    unregisterSession();
+}
+
+sp<BpDecodingService> DecodingClient::decoding_service = NULL;
+
+DecodingClient::DecodingClient()
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+
+    ProcessState::self()->startThreadPool();
+}
+
+DecodingClient::~DecodingClient()
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+}
+
+sp<BpDecodingService>& DecodingClient::service_instance()
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+    // TODO: Add a mutex here
+    if (decoding_service == NULL)
+    {
+        ALOGD("Creating a new static BpDecodingService instance");
+        sp<IServiceManager> service_manager = defaultServiceManager();
+        sp<IBinder> service = service_manager->getService(
+                String16(IDecodingService::exported_service_name()));
+        decoding_service = new BpDecodingService(service);
+    }
+
+    return decoding_service;
+}
+
+status_t DecodingClient::getIGraphicBufferConsumer(sp<IGraphicBufferConsumer>* gbc)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    return service_instance()->getIGraphicBufferConsumer(gbc);
+}
+
+// IDecodingServiceSession
+
+BpDecodingServiceSession::BpDecodingServiceSession(const sp<IBinder>& impl)
+    : BpInterface<IDecodingServiceSession>(impl)
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+}
+
+BpDecodingServiceSession::~BpDecodingServiceSession()
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+}
+
+BnDecodingServiceSession::BnDecodingServiceSession()
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+}
+
+BnDecodingServiceSession::~BnDecodingServiceSession()
+{
+    ALOGD("%s", __PRETTY_FUNCTION__);
+}
+
+status_t BnDecodingServiceSession::onTransact(uint32_t code, const Parcel& data,
+            Parcel* reply, uint32_t flags)
+{
+    ALOGD("Entering %s", __PRETTY_FUNCTION__);
+
+    return NO_ERROR;
+}
+
+// ----- C API ----- //
+
+
+}; // namespace android
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/decoding_service_priv.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef DECODING_SERVICE_PRIV_H_
+#define DECODING_SERVICE_PRIV_H_
+
+#include "surface_texture_client_hybris_priv.h"
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+typedef struct {
+    DecodingClientDeathCbHybris cb;
+    void *context;
+} ClientCb;
+
+class IGraphicBufferConsumer;
+class IGraphicBufferProducer;
+class BufferQueue;
+class GLConsumer;
+
+class IDecodingServiceSession : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(DecodingServiceSession);
+
+    static const char* exported_service_name() { return "android.media.IDecodingServiceSession"; }
+
+};
+
+class BnDecodingServiceSession : public BnInterface<IDecodingServiceSession>
+{
+public:
+    BnDecodingServiceSession();
+    virtual ~BnDecodingServiceSession();
+
+    virtual status_t onTransact(uint32_t code, const Parcel& data,
+                                Parcel* reply, uint32_t flags = 0);
+};
+
+enum {
+    SET_DECODING_CLIENT_DEATH_CB = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpDecodingServiceSession : public BpInterface<IDecodingServiceSession>
+{
+public:
+    BpDecodingServiceSession(const sp<IBinder>& impl);
+    ~BpDecodingServiceSession();
+};
+
+class IDecodingService: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(DecodingService);
+
+    static const char* exported_service_name() { return "android.media.IDecodingService"; }
+
+    virtual status_t getIGraphicBufferConsumer(sp<IGraphicBufferConsumer>* gbc) = 0;
+    virtual status_t getIGraphicBufferProducer(sp<IGraphicBufferProducer>* gbp) = 0;
+    virtual status_t registerSession(const sp<IDecodingServiceSession>& session, uint32_t handle) = 0;
+    virtual status_t unregisterSession() = 0;
+};
+
+class BnDecodingService: public BnInterface<IDecodingService>
+{
+public:
+    virtual status_t onTransact( uint32_t code,
+                                 const Parcel& data,
+                                 Parcel* reply,
+                                 uint32_t flags = 0);
+};
+
+class BpDecodingService: public BpInterface<IDecodingService>
+{
+public:
+    BpDecodingService(const sp<IBinder>& impl)
+        : BpInterface<IDecodingService>(impl)
+    {
+        ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    }
+
+    virtual status_t getIGraphicBufferConsumer(sp<IGraphicBufferConsumer>* gbc);
+    virtual status_t getIGraphicBufferProducer(sp<IGraphicBufferProducer>* gbp);
+    virtual status_t registerSession(const sp<IDecodingServiceSession>& session, uint32_t handle);
+    virtual status_t unregisterSession();
+};
+
+class DecodingService : public BnDecodingService,
+                        public IBinder::DeathRecipient
+{
+public:
+    DecodingService();
+    virtual ~DecodingService();
+    /** Adds the decoding service to the default service manager in Binder **/
+    static void instantiate();
+    static sp<DecodingService>& service_instance();
+
+    virtual void setDecodingClientDeathCb(DecodingClientDeathCbHybris cb, uint32_t handle, void* context);
+
+    // IDecodingService interface:
+    virtual status_t getIGraphicBufferConsumer(sp<IGraphicBufferConsumer>* gbc);
+    virtual status_t getIGraphicBufferProducer(sp<IGraphicBufferProducer>* gbp);
+
+    virtual status_t registerSession(const sp<IDecodingServiceSession>& session, uint32_t handle);
+    virtual status_t unregisterSession();
+
+    /** Get notified when the Binder connection to the client dies **/
+    virtual void binderDied(const wp<IBinder>& who);
+
+protected:
+    virtual void createBufferQueue();
+
+private:
+    static sp<DecodingService> decoding_service;
+#if ANDROID_VERSION_MAJOR==5
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+#else
+    sp<BufferQueue> buffer_queue;
+#endif
+    sp<IDecodingServiceSession> session;
+    DecodingClientDeathCbHybris client_death_cb;
+    void *client_death_context;
+    KeyedVector< uint32_t, ClientCb* > clients;
+    KeyedVector< sp<IBinder>, ClientCb* > clientCbs;
+};
+
+class DecodingClient
+{
+public:
+    DecodingClient();
+    virtual ~DecodingClient();
+
+    static sp<BpDecodingService>& service_instance();
+
+    virtual status_t getIGraphicBufferConsumer(sp<IGraphicBufferConsumer>* gbc);
+
+private:
+    static sp<BpDecodingService> decoding_service;
+};
+
+struct IGBCWrapper
+{
+    IGBCWrapper(const sp<IGraphicBufferConsumer>& igbc)
+    {
+        consumer = igbc;
+    }
+
+    sp<IGraphicBufferConsumer> consumer;
+};
+
+struct IGBPWrapper
+{
+    IGBPWrapper(const sp<IGraphicBufferProducer>& igbp)
+    {
+        producer = igbp;
+    }
+
+    sp<IGraphicBufferProducer> producer;
+};
+
+struct GLConsumerWrapper
+{
+    GLConsumerWrapper(const sp<_GLConsumerHybris>& gl_consumer)
+    {
+        consumer = gl_consumer;
+    }
+
+    sp<_GLConsumerHybris> consumer;
+};
+
+struct DSSessionWrapper
+{
+    DSSessionWrapper(const sp<IDecodingServiceSession>& session)
+    {
+        ALOGD("Entering %s", __PRETTY_FUNCTION__);
+        this->session = session;
+    }
+
+    ~DSSessionWrapper()
+    {
+        ALOGD("Entering %s", __PRETTY_FUNCTION__);
+    }
+
+    sp<IDecodingServiceSession> session;
+};
+
+}; // namespace android
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/direct_media_test.cpp
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ */
+
+#include <hybris/media/media_compatibility_layer.h>
+#include "direct_media_test.h"
+
+#include <utils/Errors.h>
+
+#include <hybris/surface_flinger/surface_flinger_compatibility_layer.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+using namespace android;
+
+static float DestWidth = 0.0, DestHeight = 0.0;
+// Actual video dimmensions
+static int Width = 0, Height = 0;
+
+static GLfloat positionCoordinates[8];
+
+MediaPlayerWrapper *player = NULL;
+
+void calculate_position_coordinates()
+{
+	// Assuming cropping output for now
+	float x = 1, y = 1;
+
+	// Black borders
+	x = float(Width / DestWidth);
+	y = float(Height / DestHeight);
+
+	// Make the larger side be 1
+	if (x > y) {
+		y /= x;
+		x = 1;
+	} else {
+		x /= y;
+		y = 1;
+	}
+
+	positionCoordinates[0] = -x;
+	positionCoordinates[1] = y;
+	positionCoordinates[2] = -x;
+	positionCoordinates[3] = -y;
+	positionCoordinates[4] = x;
+	positionCoordinates[5] = -y;
+	positionCoordinates[6] = x;
+	positionCoordinates[7] = y;
+}
+
+WindowRenderer::WindowRenderer(int width, int height)
+	: mThreadCmd(CMD_IDLE)
+{
+	createThread(threadStart, this);
+}
+
+WindowRenderer::~WindowRenderer()
+{
+}
+
+int WindowRenderer::threadStart(void* self)
+{
+	((WindowRenderer *)self)->glThread();
+	return 0;
+}
+
+void WindowRenderer::glThread()
+{
+	printf("%s\n", __PRETTY_FUNCTION__);
+
+	Mutex::Autolock autoLock(mLock);
+}
+
+struct ClientWithSurface
+{
+	SfClient* client;
+	SfSurface* surface;
+};
+
+ClientWithSurface client_with_surface(bool setup_surface_with_egl)
+{
+	ClientWithSurface cs = ClientWithSurface();
+
+	cs.client = sf_client_create();
+
+	if (!cs.client) {
+		printf("Problem creating client ... aborting now.");
+		return cs;
+	}
+
+	static const size_t primary_display = 0;
+
+	DestWidth = sf_get_display_width(primary_display);
+	DestHeight = sf_get_display_height(primary_display);
+	printf("Primary display width: %f, height: %f\n", DestWidth, DestHeight);
+
+	SfSurfaceCreationParameters params = {
+		0,
+		0,
+		(int) DestWidth,
+		(int) DestHeight,
+		-1, //PIXEL_FORMAT_RGBA_8888,
+		15000,
+		0.5f,
+		setup_surface_with_egl, // Do not associate surface with egl, will be done by camera HAL
+		"MediaCompatLayerTestSurface"
+	};
+
+	cs.surface = sf_surface_create(cs.client, &params);
+
+	if (!cs.surface) {
+		printf("Problem creating surface ... aborting now.");
+		return cs;
+	}
+
+	sf_surface_make_current(cs.surface);
+
+	return cs;
+}
+
+struct RenderData
+{
+	static const char *vertex_shader()
+	{
+		return
+			"attribute vec4 a_position;                                  \n"
+			"attribute vec2 a_texCoord;                                  \n"
+			"uniform mat4 m_texMatrix;                                   \n"
+			"varying vec2 v_texCoord;                                    \n"
+			"varying float topDown;                                      \n"
+			"void main()                                                 \n"
+			"{                                                           \n"
+			"   gl_Position = a_position;                                \n"
+			"   v_texCoord = (m_texMatrix * vec4(a_texCoord, 0.0, 1.0)).xy;\n"
+			"}                                                           \n";
+	}
+
+	static const char *fragment_shader()
+	{
+		return
+			"#extension GL_OES_EGL_image_external : require      \n"
+			"precision mediump float;                            \n"
+			"varying vec2 v_texCoord;                            \n"
+			"uniform samplerExternalOES s_texture;               \n"
+			"void main()                                         \n"
+			"{                                                   \n"
+			"  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
+			"}                                                   \n";
+	}
+
+	static GLuint loadShader(GLenum shaderType, const char* pSource)
+	{
+		GLuint shader = glCreateShader(shaderType);
+
+		if (shader) {
+			glShaderSource(shader, 1, &pSource, NULL);
+			glCompileShader(shader);
+			GLint compiled = 0;
+			glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+
+			if (!compiled) {
+				GLint infoLen = 0;
+				glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+				if (infoLen) {
+					char* buf = (char*) malloc(infoLen);
+					if (buf) {
+						glGetShaderInfoLog(shader, infoLen, NULL, buf);
+						fprintf(stderr, "Could not compile shader %d:\n%s\n",
+								shaderType, buf);
+						free(buf);
+					}
+					glDeleteShader(shader);
+					shader = 0;
+				}
+			}
+		} else {
+			printf("Error, during shader creation: %i\n", glGetError());
+		}
+
+		return shader;
+	}
+
+	static GLuint create_program(const char* pVertexSource, const char* pFragmentSource)
+	{
+		GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+		if (!vertexShader) {
+			printf("vertex shader not compiled\n");
+			return 0;
+		}
+
+		GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+		if (!pixelShader) {
+			printf("frag shader not compiled\n");
+			return 0;
+		}
+
+		GLuint program = glCreateProgram();
+		if (program) {
+			glAttachShader(program, vertexShader);
+			glAttachShader(program, pixelShader);
+			glLinkProgram(program);
+			GLint linkStatus = GL_FALSE;
+			glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+
+			if (linkStatus != GL_TRUE) {
+				GLint bufLength = 0;
+				glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+				if (bufLength) {
+					char* buf = (char*) malloc(bufLength);
+					if (buf) {
+						glGetProgramInfoLog(program, bufLength, NULL, buf);
+						fprintf(stderr, "Could not link program:\n%s\n", buf);
+						free(buf);
+					}
+				}
+				glDeleteProgram(program);
+				program = 0;
+			}
+		}
+
+		return program;
+	}
+
+	RenderData() : program_object(create_program(vertex_shader(), fragment_shader()))
+	{
+		position_loc = glGetAttribLocation(program_object, "a_position");
+		tex_coord_loc = glGetAttribLocation(program_object, "a_texCoord");
+		sampler_loc = glGetUniformLocation(program_object, "s_texture");
+		matrix_loc = glGetUniformLocation(program_object, "m_texMatrix");
+	}
+
+	// Handle to a program object
+	GLuint program_object;
+	// Attribute locations
+	GLint position_loc;
+	GLint tex_coord_loc;
+	// Sampler location
+	GLint sampler_loc;
+	// Matrix location
+	GLint matrix_loc;
+};
+
+static int setup_video_texture(ClientWithSurface *cs, GLuint *preview_texture_id)
+{
+	assert(cs != NULL);
+	assert(preview_texture_id != NULL);
+
+	sf_surface_make_current(cs->surface);
+
+	glGenTextures(1, preview_texture_id);
+	glClearColor(0, 0, 0, 0);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+	android_media_set_preview_texture(player, *preview_texture_id);
+
+	return 0;
+}
+
+static void print_gl_error(unsigned int line)
+{
+	GLint error = glGetError();
+	printf("GL error: %#04x (line: %d)\n", error, line);
+}
+
+static int update_gl_buffer(RenderData *render_data, EGLDisplay *disp, EGLSurface *surface)
+{
+	assert(disp != NULL);
+	assert(surface != NULL);
+
+	GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+	const GLfloat textureCoordinates[] = {
+		1.0f,  1.0f,
+		0.0f,  1.0f,
+		0.0f,  0.0f,
+		1.0f,  0.0f
+	};
+
+	calculate_position_coordinates();
+
+	glClear(GL_COLOR_BUFFER_BIT);
+	// Use the program object
+	glUseProgram(render_data->program_object);
+	// Enable attributes
+	glEnableVertexAttribArray(render_data->position_loc);
+	glEnableVertexAttribArray(render_data->tex_coord_loc);
+	// Load the vertex position
+	glVertexAttribPointer(render_data->position_loc,
+			2,
+			GL_FLOAT,
+			GL_FALSE,
+			0,
+			positionCoordinates);
+	// Load the texture coordinate
+	glVertexAttribPointer(render_data->tex_coord_loc,
+			2,
+			GL_FLOAT,
+			GL_FALSE,
+			0,
+			textureCoordinates);
+
+	GLfloat matrix[16];
+	android_media_surface_texture_get_transformation_matrix(player, matrix);
+
+	glUniformMatrix4fv(render_data->matrix_loc, 1, GL_FALSE, matrix);
+
+	glActiveTexture(GL_TEXTURE0);
+	// Set the sampler texture unit to 0
+	glUniform1i(render_data->sampler_loc, 0);
+	glUniform1i(render_data->matrix_loc, 0);
+	android_media_update_surface_texture(player);
+	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+	//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+	glDisableVertexAttribArray(render_data->position_loc);
+	glDisableVertexAttribArray(render_data->tex_coord_loc);
+
+	eglSwapBuffers(*disp, *surface);
+
+	return 0;
+}
+
+void set_video_size_cb(int height, int width, void *context)
+{
+	printf("Video height: %d, width: %d\n", height, width);
+	printf("Video dest height: %f, width: %f\n", DestHeight, DestWidth);
+
+	Height = height;
+	Width = width;
+}
+
+int main(int argc, char **argv)
+{
+	if (argc < 2) {
+		printf("Usage: direct_media_test <video_to_play>\n");
+		return EXIT_FAILURE;
+	}
+
+	player = android_media_new_player();
+	if (player == NULL) {
+		printf("Problem creating new media player.\n");
+		return EXIT_FAILURE;
+	}
+
+	// Set player event cb for when the video size is known:
+	android_media_set_video_size_cb(player, set_video_size_cb, NULL);
+
+	printf("Setting data source to: %s.\n", argv[1]);
+
+	if (android_media_set_data_source(player, argv[1]) != OK) {
+		printf("Failed to set data source: %s\n", argv[1]);
+		return EXIT_FAILURE;
+	}
+
+	WindowRenderer renderer(DestWidth, DestHeight);
+
+	printf("Creating EGL surface.\n");
+	ClientWithSurface cs = client_with_surface(true /* Associate surface with egl. */);
+	if (!cs.surface) {
+		printf("Problem acquiring surface for preview");
+		return EXIT_FAILURE;
+	}
+
+	printf("Creating GL texture.\n");
+	GLuint preview_texture_id;
+	EGLDisplay disp = sf_client_get_egl_display(cs.client);
+	EGLSurface surface = sf_surface_get_egl_surface(cs.surface);
+
+	sf_surface_make_current(cs.surface);
+	if (setup_video_texture(&cs, &preview_texture_id) != OK) {
+		printf("Problem setting up GL texture for video surface.\n");
+		return EXIT_FAILURE;
+	}
+
+	RenderData render_data;
+
+	printf("Starting video playback.\n");
+	android_media_play(player);
+
+	printf("Updating gl buffer continuously...\n");
+	while (android_media_is_playing(player)) {
+		update_gl_buffer(&render_data, &disp, &surface);
+	}
+
+	android_media_stop(player);
+
+	return EXIT_SUCCESS;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/direct_media_test.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef DIRECT_MEDIA_TEST_H_
+#define DIRECT_MEDIA_TEST_H_
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class RenderInput;
+
+class WindowRenderer
+{
+public:
+    WindowRenderer(int width, int height);
+    ~WindowRenderer();
+
+private:
+    // The GL thread functions
+    static int threadStart(void* self);
+    void glThread();
+
+    // These variables are used to communicate between the GL thread and
+    // other threads.
+    Mutex mLock;
+    Condition mCond;
+    enum {
+        CMD_IDLE,
+        CMD_RENDER_INPUT,
+        CMD_RESERVE_TEXTURE,
+        CMD_DELETE_TEXTURE,
+        CMD_QUIT,
+    };
+    int mThreadCmd;
+    RenderInput* mThreadRenderInput;
+    GLuint mThreadTextureId;
+};
+} // android
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_codec_layer.cpp
@@ -0,0 +1,879 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+// Uncomment to enable verbose debug output
+#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "MediaCodecLayer"
+
+#include <hybris/media/media_codec_layer.h>
+#include <hybris/media/media_compatibility_layer.h>
+#include <hybris/media/media_format_layer.h>
+
+#include "media_format_layer_priv.h"
+#include "surface_texture_client_hybris_priv.h"
+#include "decoding_service_priv.h"
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <binder/ProcessState.h>
+
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/ICrypto.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/NativeWindowWrapper.h>
+
+#include <gui/IGraphicBufferProducer.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/Vector.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+#include <utils/Mutex.h>
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__);
+
+using namespace android;
+
+struct _MediaCodecDelegate : public AHandler
+{
+public:
+    typedef sp<_MediaCodecDelegate> Ptr;
+
+    explicit _MediaCodecDelegate(void *context);
+    virtual ~_MediaCodecDelegate();
+
+protected:
+    virtual void onMessageReceived(const sp<AMessage> &msg) { }
+
+public:
+    sp<MediaCodec> media_codec;
+    sp<ALooper> looper;
+
+    Vector<sp<ABuffer> > input_buffers;
+    Vector<sp<ABuffer> > output_buffers;
+    List<MediaCodecBufferInfo> available_output_buffer_infos;
+    Mutex mtx_output_buffer_infos;
+    List<size_t> available_input_buffer_indices;
+    bool output_format_changed;
+    bool hardware_rendering;
+
+    void *context;
+    unsigned int refcount;
+};
+
+_MediaCodecDelegate::_MediaCodecDelegate(void *context)
+    : output_format_changed(false),
+      hardware_rendering(false),
+      context(context),
+      refcount(1)
+{
+    REPORT_FUNCTION()
+}
+
+_MediaCodecDelegate::~_MediaCodecDelegate()
+{
+    REPORT_FUNCTION()
+}
+
+static inline _MediaCodecDelegate *get_internal_delegate(MediaCodecDelegate delegate)
+{
+    if (delegate == NULL)
+    {
+        ALOGE("delegate must not be NULL");
+        return NULL;
+    }
+
+    _MediaCodecDelegate *d = static_cast<_MediaCodecDelegate*>(delegate);
+    // Some simple sanity checks that must be true for a valid MediaCodecDelegate instance
+    if (d->media_codec == NULL || d->refcount < 1)
+        return NULL;
+
+    return d;
+}
+
+// ----- DecodingService C API ----- //
+//
+// FIXME: These functions really need to be moved into decoding_service.cpp, but for some
+// reason were segfaulting when I tried them in there last
+
+namespace {
+
+    DecodingClient& decoding_client_instance()
+    {
+        static DecodingClient instance;
+        return instance;
+    }
+}
+
+void decoding_service_init()
+{
+    REPORT_FUNCTION();
+
+    // Register the service with Binder ServiceManager
+    DecodingService::instantiate();
+
+    ProcessState::self()->startThreadPool();
+}
+
+IGBCWrapperHybris decoding_service_get_igraphicbufferconsumer()
+{
+    REPORT_FUNCTION();
+
+    sp<IGraphicBufferConsumer> consumer;
+    decoding_client_instance().getIGraphicBufferConsumer(&consumer);
+    IGBCWrapper *wrapper = new IGBCWrapper(consumer);
+    return wrapper;
+}
+
+IGBPWrapperHybris decoding_service_get_igraphicbufferproducer()
+{
+    REPORT_FUNCTION();
+
+    sp<IServiceManager> service_manager = defaultServiceManager();
+    sp<IBinder> service = service_manager->getService(
+            String16(IDecodingService::exported_service_name()));
+
+    sp<IGraphicBufferProducer> producer;
+    DecodingClient::service_instance()->getIGraphicBufferProducer(&producer);
+    IGBPWrapper *wrapper = new IGBPWrapper(producer);
+
+    return wrapper;
+}
+
+DSSessionWrapperHybris decoding_service_create_session(uint32_t handle)
+{
+    REPORT_FUNCTION();
+
+    sp<IServiceManager> service_manager = defaultServiceManager();
+    sp<IBinder> service = service_manager->getService(
+            String16(IDecodingService::exported_service_name()));
+
+    // Create a new decoding service session
+    sp<BnDecodingServiceSession> session(new BnDecodingServiceSession());
+    // This new session will destroy and replace any existing session
+    DecodingClient::service_instance()->registerSession(session, handle);
+    DSSessionWrapper *wrapper(new DSSessionWrapper(session));
+
+    return wrapper;
+}
+
+void decoding_service_set_client_death_cb(DecodingClientDeathCbHybris cb, uint32_t handle, void *context)
+{
+    REPORT_FUNCTION();
+
+    if (cb == NULL)
+    {
+        ALOGE("cb must not be NULL");
+        return;
+    }
+
+    DecodingService::service_instance()->setDecodingClientDeathCb(cb, handle, context);
+}
+
+// ----- End of DecodingService C API ----- //
+
+MediaCodecDelegate media_codec_create_by_codec_name(const char *name)
+{
+    REPORT_FUNCTION()
+
+    if (name == NULL)
+    {
+        ALOGE("name must not be NULL");
+        return NULL;
+    }
+
+    ALOGD("Creating codec '%s'", name);
+
+    ProcessState::self()->startThreadPool();
+
+    _MediaCodecDelegate *d(new _MediaCodecDelegate(NULL));
+    d->looper = new ALooper;
+    d->looper->start();
+
+    d->media_codec = android::MediaCodec::CreateByComponentName(d->looper, name);
+
+    return d;
+}
+
+#ifdef SIMPLE_PLAYER
+MediaCodec* media_codec_get(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return NULL;
+
+    return d->media_codec.get();
+}
+#endif
+
+MediaCodecDelegate media_codec_create_by_codec_type(const char *type)
+{
+    REPORT_FUNCTION()
+
+    if (type == NULL)
+    {
+        ALOGE("type must not be NULL");
+        return NULL;
+    }
+
+    ALOGD("Creating codec by type '%s'", type);
+
+    ProcessState::self()->startThreadPool();
+
+    _MediaCodecDelegate *d(new _MediaCodecDelegate(NULL));
+    d->looper = new ALooper;
+    d->looper->start();
+
+    d->media_codec = android::MediaCodec::CreateByType(d->looper, type, false);
+
+    return d;
+}
+
+void media_codec_delegate_destroy(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+    {
+        ALOGE("d == NULL, cannot destroy MediaCodecDelegate instance");
+        return;
+    }
+
+    ALOGI("Releasing media_codec");
+    d->media_codec->release();
+    ALOGI("Stopping looper");
+    d->looper->stop();
+
+    ALOGI("Setting refcount = 0");
+    d->refcount = 0;
+
+    ALOGI("Deleting the MediaCodecDelegate instance");
+    delete d;
+}
+
+void media_codec_delegate_ref(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return;
+
+    d->refcount++;
+}
+
+void media_codec_delegate_unref(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+    {
+        ALOGE("d == NULL, cannot unref MediaCodecDelegate instance");
+        return;
+    }
+
+    if (d->refcount > 1)
+        d->refcount--;
+    else
+        media_codec_delegate_destroy (delegate);
+}
+
+#ifdef SIMPLE_PLAYER
+int media_codec_configure(MediaCodecDelegate delegate, MediaFormat format, void *nativeWindow, uint32_t flags)
+#else
+int media_codec_configure(MediaCodecDelegate delegate, MediaFormat format, SurfaceTextureClientHybris stc, uint32_t flags)
+#endif
+{
+    REPORT_FUNCTION()
+
+    if (format == NULL)
+    {
+        ALOGE("format must not be NULL");
+        return BAD_VALUE;
+    }
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    _MediaFormat *format_priv = static_cast<_MediaFormat*>(format);
+#ifndef SIMPLE_PLAYER
+    _SurfaceTextureClientHybris *stch = static_cast<_SurfaceTextureClientHybris*>(stc);
+#endif
+
+    sp<AMessage> aformat = new AMessage;
+    aformat->setString("mime", format_priv->mime.c_str());
+    if (format_priv->duration_us > 0)
+        aformat->setInt64("durationUs", format_priv->duration_us);
+    aformat->setInt32("width", format_priv->width);
+    aformat->setInt32("height", format_priv->height);
+    if (format_priv->max_input_size > 0)
+        aformat->setInt32("max-input-size", format_priv->max_input_size);
+
+    if (format_priv->csd.get() != NULL) {
+        const size_t csd_size = format_priv->csd->size();
+
+        ALOGD("Adding csd (%zu bytes)", csd_size);
+
+        sp<ABuffer> buffer = new ABuffer(csd_size);
+        memcpy(buffer->data(), format_priv->csd->data(), csd_size);
+
+        buffer->meta()->setInt32("csd", true);
+        buffer->meta()->setInt64("timeUs", 0);
+        aformat->setBuffer("csd-0", buffer);
+    }
+
+    ALOGD("Format: %s", aformat->debugString().c_str());
+
+#ifdef SIMPLE_PLAYER
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    sp<SurfaceTextureClient> surfaceTextureClient = static_cast<SurfaceTextureClient*>(nativeWindow);
+#else
+    sp<Surface> surfaceTextureClient = static_cast<Surface*>(nativeWindow);
+#endif
+    // TODO: Don't just pass NULL for the security when DRM is needed
+    d->media_codec->configure(aformat, surfaceTextureClient, NULL, flags);
+#else
+    ALOGD("SurfaceTextureClientHybris: %p", stch);
+
+    // Make sure we're ready to configure the codec and the Surface/SurfaceTextureClient together
+    if (stch != NULL && stch->hardwareRendering() && stch->isReady())
+    {
+        ALOGD("Doing hardware decoding with hardware rendering");
+        // TODO: Don't just pass NULL for the security when DRM is needed
+        d->media_codec->configure(aformat, stch, NULL, flags);
+    }
+    else
+    {
+        ALOGD("Doing hardware decoding path with software rendering");
+        // This scenario is for hardware video decoding, but software rendering, therefore there's
+        // no need to pass a valid Surface/SurfaceTextureClient instance to configure()
+        d->media_codec->configure(aformat, NULL, NULL, flags);
+    }
+#endif
+
+    return OK;
+}
+
+int media_codec_set_surface_texture_client(MediaCodecDelegate delegate, SurfaceTextureClientHybris stc)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+    if (stc == NULL)
+    {
+        ALOGE("stc must not be NULL");
+        return BAD_VALUE;
+    }
+
+    _SurfaceTextureClientHybris *stcu = static_cast<_SurfaceTextureClientHybris*>(stc);
+    status_t err = native_window_api_connect(stcu, NATIVE_WINDOW_API_MEDIA);
+    if (err != OK)
+    {
+        ALOGE("native_window_api_connect returned an error: %s (%d)", strerror(-err), err);
+        return err;
+    }
+
+    return OK;
+}
+
+int media_codec_queue_csd(MediaCodecDelegate delegate, MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    if (format == NULL)
+    {
+        ALOGE("format must not be NULL");
+        return BAD_VALUE;
+    }
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    _MediaFormat *format_priv = static_cast<_MediaFormat*>(format);
+    assert(format_priv->csd != NULL);
+
+    status_t err = OK;
+
+    Vector<sp<ABuffer> > input_bufs[1];
+    err = d->media_codec->getInputBuffers(&input_bufs[0]);
+    CHECK_EQ(err, static_cast<status_t>(OK));
+
+    for (size_t i=0; i<2; ++i)
+    {
+        const sp<ABuffer> &srcBuffer = format_priv->csd;
+
+        size_t index = 0;
+        err = d->media_codec->dequeueInputBuffer(&index, -1ll);
+        CHECK_EQ(err, static_cast<status_t>(OK));
+
+        const sp<ABuffer> &dstBuffer = input_bufs[0].itemAt(index);
+
+        CHECK_LE(srcBuffer->size(), dstBuffer->capacity());
+        dstBuffer->setRange(0, srcBuffer->size());
+        memcpy(dstBuffer->data(), srcBuffer->data(), srcBuffer->size());
+
+        dstBuffer->meta()->setInt32("csd", true);
+        dstBuffer->meta()->setInt64("timeUs", 0);
+
+        AString err_msg;
+        err = d->media_codec->queueInputBuffer(
+                index,
+                0,
+                dstBuffer->size(),
+                0ll,
+                MediaCodec::BUFFER_FLAG_CODECCONFIG);
+        CHECK_EQ(err, static_cast<status_t>(OK));
+    }
+
+    return err;
+}
+
+int media_codec_start(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    return d->media_codec->start();
+}
+
+int media_codec_stop(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    return d->media_codec->stop();
+}
+
+int media_codec_release(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    return d->media_codec->release();
+}
+
+int media_codec_flush(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    d->mtx_output_buffer_infos.lock();
+
+    d->available_output_buffer_infos.clear();
+
+    d->mtx_output_buffer_infos.unlock();
+
+    return d->media_codec->flush();
+}
+
+size_t media_codec_get_input_buffers_size(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    status_t ret = d->media_codec->getInputBuffers(&d->input_buffers);
+    if (ret != OK)
+    {
+        ALOGE("Failed to get input buffers size");
+        return 0;
+    }
+    ALOGD("Got %d input buffers", d->input_buffers.size());
+
+    return d->input_buffers.size();
+}
+
+uint8_t *media_codec_get_nth_input_buffer(MediaCodecDelegate delegate, size_t n)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return NULL;
+
+    if (d->input_buffers.size() == 0)
+    {
+        status_t ret = d->media_codec->getInputBuffers(&d->input_buffers);
+        if (ret != OK)
+        {
+            ALOGE("Failed to get input buffers");
+            return NULL;
+        }
+    }
+
+    if (n > d->input_buffers.size())
+    {
+      ALOGE("Failed to get %uth input buffer, n > total buffer size", n);
+      return NULL;
+    }
+
+    return d->input_buffers.itemAt(n).get()->data();
+}
+
+size_t media_codec_get_nth_input_buffer_capacity(MediaCodecDelegate delegate, size_t n)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    Vector<sp<ABuffer> > input_buffers;
+    status_t ret = d->media_codec->getInputBuffers(&input_buffers);
+    if (ret != OK)
+    {
+        ALOGE("Failed to get input buffers");
+        return 0;
+    }
+
+    if (n > input_buffers.size())
+    {
+      ALOGE("Failed to get %uth input buffer capacity, n > total buffer size", n);
+      return 0;
+    }
+
+    return input_buffers[n].get()->capacity();
+}
+
+size_t media_codec_get_output_buffers_size(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    status_t ret = d->media_codec->getOutputBuffers(&d->output_buffers);
+    if (ret != OK)
+    {
+        ALOGE("Failed to get output buffers size");
+        return 0;
+    }
+    ALOGD("Got %d output buffers", d->output_buffers.size());
+
+    return d->output_buffers.size();
+}
+
+uint8_t *media_codec_get_nth_output_buffer(MediaCodecDelegate delegate, size_t n)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return NULL;
+
+    status_t ret = d->media_codec->getOutputBuffers(&d->output_buffers);
+    if (ret != OK)
+    {
+        ALOGE("Failed to get output buffers");
+        return NULL;
+    }
+
+    if (n > d->output_buffers.size())
+    {
+      ALOGE("Failed to get %uth output buffer, n > total buffer size", n);
+      return NULL;
+    }
+
+    return d->output_buffers.itemAt(n).get()->data();
+}
+
+size_t media_codec_get_nth_output_buffer_capacity(MediaCodecDelegate delegate, size_t n)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    status_t ret = d->media_codec->getOutputBuffers(&d->output_buffers);
+    if (ret != OK)
+    {
+        ALOGE("Failed to get output buffers");
+        return 0;
+    }
+
+    if (n > d->output_buffers.size())
+    {
+      ALOGE("Failed to get %uth output buffer capacity, n > total buffer size", n);
+      return 0;
+    }
+
+    return d->output_buffers[n].get()->capacity();
+}
+
+#define INFO_TRY_AGAIN_LATER        -1
+#define INFO_OUTPUT_FORMAT_CHANGED  -2
+#define INFO_OUTPUT_BUFFERS_CHANGED -4
+
+int media_codec_dequeue_output_buffer(MediaCodecDelegate delegate, MediaCodecBufferInfo *info, int64_t timeout_us)
+{
+    REPORT_FUNCTION()
+
+    if (info == NULL)
+    {
+        ALOGE("info must not be NULL");
+        return BAD_VALUE;
+    }
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    int ret = d->media_codec->dequeueOutputBuffer(&info->index, &info->offset, &info->size, &info->presentation_time_us, &info->flags, timeout_us);
+    ALOGD("dequeueOutputBuffer() ret: %d", ret);
+    info->render_retries = 0;
+
+    if (ret == -EAGAIN)
+    {
+        ALOGD("dequeueOutputBuffer returned %d", ret);
+        return INFO_TRY_AGAIN_LATER;
+    }
+    else if (ret & ~INFO_OUTPUT_BUFFERS_CHANGED)
+    {
+        ALOGD("Output buffers changed (ret: %d)", ret);
+        return INFO_OUTPUT_BUFFERS_CHANGED + 1;
+    }
+    // FIXME: Get rid of the hardcoded -10 and replace with more elegant solution
+    else if (ret & ~(INFO_FORMAT_CHANGED - 10))
+    {
+        ALOGD("Output buffer format changed (ret: %d)", ret);
+        d->output_format_changed = true;
+        return -2;
+    }
+
+    ALOGD("Dequeued output buffer:\n-----------------------");
+    ALOGD("index: %u", info->index);
+    ALOGD("offset: %d", info->offset);
+    ALOGD("size: %d", info->size);
+    ALOGD("presentation_time_us: %lld", info->presentation_time_us);
+    ALOGD("flags: %d", info->flags);
+
+    d->mtx_output_buffer_infos.lock();
+
+    // Keep track of the used output buffer info
+    d->available_output_buffer_infos.push_back(*info);
+
+    d->mtx_output_buffer_infos.unlock();
+
+    return OK;
+}
+
+int media_codec_queue_input_buffer(MediaCodecDelegate delegate, const MediaCodecBufferInfo *info)
+{
+    REPORT_FUNCTION()
+
+    if (info == NULL)
+    {
+        ALOGE("info must not be NULL");
+        return BAD_VALUE;
+    }
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    // Make sure that there is at least one dequeued input buffer available
+    if (d->available_input_buffer_indices.empty())
+    {
+        ALOGE("Input buffer index %d has not been dequeued, cannot queue input buffer", info->index);
+        return BAD_VALUE;
+    }
+
+    const size_t index = *d->available_input_buffer_indices.begin();
+    d->available_input_buffer_indices.erase(d->available_input_buffer_indices.begin());
+
+    ALOGD("info->index: %d", index);
+    ALOGD("info->offset: %d", info->offset);
+    ALOGD("info->size: %d", info->size);
+    ALOGD("info->presentation_time_us: %lld", info->presentation_time_us);
+    ALOGD("info->flags: %d", info->flags);
+
+    AString err_msg;
+    status_t ret = d->media_codec->queueInputBuffer(index, info->offset, info->size,
+            info->presentation_time_us, info->flags, &err_msg);
+    if (ret != OK)
+    {
+        ALOGE("Failed to queue input buffer (err: %d, index: %d)", ret, index);
+        ALOGE("Detailed error message: %s", err_msg.c_str());
+    }
+
+    return ret;
+}
+
+int media_codec_dequeue_input_buffer(MediaCodecDelegate delegate, size_t *index, int64_t timeout_us)
+{
+    REPORT_FUNCTION()
+
+    if (index == NULL)
+    {
+        ALOGE("index must not be NULL");
+        return BAD_VALUE;
+    }
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    status_t ret = d->media_codec->dequeueInputBuffer(index, timeout_us);
+    if (ret == -EAGAIN)
+    {
+        ALOGD("dequeueInputBuffer returned %d, tried timeout: %lld", ret, timeout_us);
+        return INFO_TRY_AGAIN_LATER;
+    }
+    else if (ret == OK)
+    {
+        ALOGD("Dequeued input buffer (index: %d)", *index);
+        d->available_input_buffer_indices.push_back(*index);
+    }
+    else
+        ALOGE("Failed to dequeue input buffer (err: %d, index: %d)", ret, *index);
+
+    return ret;
+}
+
+int media_codec_release_output_buffer(MediaCodecDelegate delegate, size_t index, uint8_t render)
+{
+    REPORT_FUNCTION()
+    ALOGV("Requesting to release output buffer index: %d, render: %d", index, render);
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return BAD_VALUE;
+
+    status_t ret = OK;
+
+    /* This function can be called from multiple threads from gstreamer */
+    Mutex::Autolock autoLock(d->mtx_output_buffer_infos);
+
+    auto it = d->available_output_buffer_infos.begin();
+    while (it != d->available_output_buffer_infos.end())
+    {
+        MediaCodecBufferInfo *info = &*it;
+        ALOGD("info index: %d", info->index);
+        ALOGD("info render_retries: %u", info->render_retries);
+        if (info->render_retries == 1)
+        {
+            ALOGV("Rendering and releasing output buffer %d from the available indices list", info->index);
+            ret = d->media_codec->renderOutputBufferAndRelease(info->index);
+            if (ret != OK)
+            {
+                ALOGE("Failed to release output buffer (ret: %d, index: %d)", ret, info->index);
+                ++info->render_retries;
+            }
+            else
+            {
+                ALOGV("Successfully rendered output buffer %d on a second try.", info->index);
+                d->available_output_buffer_infos.erase(it);
+            }
+        }
+        else if (info->render_retries > 1)
+        {
+            ALOGV("Tried to render output buffer %d twice, dropping.", info->index);
+            ret = d->media_codec->releaseOutputBuffer(info->index);
+            d->available_output_buffer_infos.erase(d->available_output_buffer_infos.begin());
+        }
+
+        ++it;
+    }
+
+    MediaCodecBufferInfo *info = &*d->available_output_buffer_infos.begin();
+    // Either render and release the output buffer, or just release.
+    if (render)
+    {
+        ALOGV("Rendering and releasing output buffer %d from the available indices list", info->index);
+        ret = d->media_codec->renderOutputBufferAndRelease(info->index);
+    }
+    else
+    {
+        ALOGV("Releasing output buffer %d from the available indices list", info->index);
+        ret = d->media_codec->releaseOutputBuffer(info->index);
+    }
+    if (ret != OK)
+    {
+        ALOGE("Failed to release output buffer (ret: %d, index: %d)", ret, info->index);
+        ++info->render_retries;
+    } else {
+        ALOGV("Released output buffer %d from the available buffer infos list", info->index);
+        d->available_output_buffer_infos.erase(d->available_output_buffer_infos.begin());
+    }
+
+    return ret;
+}
+
+MediaFormat media_codec_get_output_format(MediaCodecDelegate delegate)
+{
+    REPORT_FUNCTION()
+
+    _MediaCodecDelegate *d = get_internal_delegate(delegate);
+    if (d == NULL)
+        return NULL;
+
+    _MediaFormat *f = new _MediaFormat();
+
+    sp<AMessage> msg_format;
+    status_t ret = d->media_codec->getOutputFormat(&msg_format);
+    if (ret != OK)
+    {
+        ALOGE("Failed to get the output format");
+        return NULL;
+    }
+
+    ALOGD("Output format: %s", msg_format->debugString().c_str());
+
+    CHECK(msg_format->findString("mime", &f->mime));
+    CHECK(msg_format->findInt32("width", &f->width));
+    CHECK(msg_format->findInt32("height", &f->height));
+    CHECK(msg_format->findInt32("stride", &f->stride));
+    CHECK(msg_format->findInt32("slice-height", &f->slice_height));
+    CHECK(msg_format->findInt32("color-format", &f->color_format));
+    Rect crop;
+    CHECK(msg_format->findRect("crop", &crop.left, &crop.top, &crop.right, &crop.bottom));
+
+    return f;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_codec_list.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+// Uncomment to enable verbose debug output
+#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "MediaCodecList"
+
+#include <hybris/media/media_codec_list.h>
+
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/MediaCodecList.h>
+
+#include <utils/Log.h>
+#include <utils/Vector.h>
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__);
+
+using namespace android;
+
+ssize_t media_codec_list_find_codec_by_type(const char *type, bool encoder, size_t startIndex)
+{
+    REPORT_FUNCTION()
+    return MediaCodecList::getInstance()->findCodecByType(type, encoder, startIndex);
+}
+
+ssize_t media_codec_list_find_codec_by_name(const char *name)
+{
+    REPORT_FUNCTION()
+    return MediaCodecList::getInstance()->findCodecByName(name);
+}
+
+size_t media_codec_list_count_codecs()
+{
+    REPORT_FUNCTION()
+    return MediaCodecList::getInstance()->countCodecs();
+}
+
+void media_codec_list_get_codec_info_at_id(size_t index)
+{
+    REPORT_FUNCTION()
+}
+
+const char *media_codec_list_get_codec_name(size_t index)
+{
+    REPORT_FUNCTION()
+#if ANDROID_VERSION_MAJOR==5
+    return MediaCodecList::getInstance()->getCodecInfo(index)->getCodecName();
+#else
+    return MediaCodecList::getInstance()->getCodecName(index);
+#endif
+}
+
+bool media_codec_list_is_encoder(size_t index)
+{
+    REPORT_FUNCTION()
+#if ANDROID_VERSION_MAJOR==5
+    return MediaCodecList::getInstance()->getCodecInfo(index)->isEncoder();
+#else
+    return MediaCodecList::getInstance()->isEncoder(index);
+#endif
+}
+
+size_t media_codec_list_get_num_supported_types(size_t index)
+{
+    REPORT_FUNCTION()
+
+    Vector<AString> types;
+#if ANDROID_VERSION_MAJOR==5
+    MediaCodecList::getInstance()->getCodecInfo(index)->getSupportedMimes(&types);
+#else
+    status_t err = MediaCodecList::getInstance()->getSupportedTypes(index, &types);
+    if (err != OK)
+    {
+        ALOGE("Failed to get the number of supported codec types (err: %d)", err);
+        return 0;
+    }
+#endif
+    ALOGD("Number of supported codec types: %d", types.size());
+
+    return types.size();
+}
+
+size_t media_codec_list_get_nth_supported_type_len(size_t index, size_t n)
+{
+    REPORT_FUNCTION()
+
+    Vector<AString> types;
+#if ANDROID_VERSION_MAJOR==5
+    MediaCodecList::getInstance()->getCodecInfo(index)->getSupportedMimes(&types);
+#else
+    status_t err = MediaCodecList::getInstance()->getSupportedTypes(index, &types);
+#endif
+
+    return types[n].size();
+}
+
+int media_codec_list_get_nth_supported_type(size_t index, char *type, size_t n)
+{
+    REPORT_FUNCTION()
+
+    if (type == NULL)
+    {
+        ALOGE("types must not be NULL");
+        return BAD_VALUE;
+    }
+
+    Vector<AString> types;
+#if ANDROID_VERSION_MAJOR==5
+    MediaCodecList::getInstance()->getCodecInfo(index)->getSupportedMimes(&types);
+#else
+    status_t err = MediaCodecList::getInstance()->getSupportedTypes(index, &types);
+#endif
+    for (size_t i=0; i<types[n].size(); ++i)
+        type[i] = types.itemAt(n).c_str()[i];
+
+#if ANDROID_VERSION_MAJOR==5
+    return OK;
+#else
+    return err;
+#endif
+}
+
+static void media_codec_list_get_num_codec_capabilities(size_t index, const char *type, size_t *num_profile_levels, size_t *num_color_formats)
+{
+    REPORT_FUNCTION()
+
+#if ANDROID_VERSION_MAJOR==5
+    Vector<MediaCodecInfo::ProfileLevel> profile_levels;
+#else
+    Vector<MediaCodecList::ProfileLevel> profile_levels;
+#endif
+    Vector<uint32_t> color_formats;
+    ALOGD("index: %d, type: '%s'", index, type);
+#if ANDROID_VERSION_MAJOR==5
+    MediaCodecList::getInstance()->getCodecInfo(index)->getCapabilitiesFor(type)->getSupportedProfileLevels(&profile_levels);
+    MediaCodecList::getInstance()->getCodecInfo(index)->getCapabilitiesFor(type)->getSupportedColorFormats(&color_formats);
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
+    status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &color_formats);
+#else
+    uint32_t flags;
+    status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &color_formats, &flags);
+#endif
+#if ANDROID_VERSION_MAJOR<5
+    if (err != OK)
+    {
+        ALOGE("Failed to get the number of supported codec capabilities (err: %d)", err);
+        return;
+    }
+#endif
+
+    if (num_profile_levels != NULL)
+    {
+        ALOGD("Number of codec profile levels: %d", profile_levels.size());
+        *num_profile_levels = profile_levels.size();
+    }
+    if (num_color_formats != NULL)
+    {
+        ALOGD("Number of codec color formats: %d", color_formats.size());
+        *num_color_formats = color_formats.size();
+    }
+}
+
+size_t media_codec_list_get_num_profile_levels(size_t index, const char *type)
+{
+    REPORT_FUNCTION()
+
+    size_t num = 0;
+    media_codec_list_get_num_codec_capabilities(index, type, &num, NULL);
+
+    return num;
+}
+
+size_t media_codec_list_get_num_color_formats(size_t index, const char *type)
+{
+    REPORT_FUNCTION()
+
+    size_t num = 0;
+    media_codec_list_get_num_codec_capabilities(index, type, NULL, &num);
+
+    return num;
+}
+
+int media_codec_list_get_nth_codec_profile_level(size_t index, const char *type, profile_level *pro_level, size_t n)
+{
+    REPORT_FUNCTION()
+
+    if (type == NULL)
+    {
+        ALOGE("types must not be NULL");
+        return BAD_VALUE;
+    }
+
+    if (pro_level == NULL)
+    {
+        ALOGE("pro_level must not be NULL");
+        return BAD_VALUE;
+    }
+
+#if ANDROID_VERSION_MAJOR==5
+    Vector<MediaCodecInfo::ProfileLevel> profile_levels;
+#else
+    Vector<MediaCodecList::ProfileLevel> profile_levels;
+#endif
+    Vector<uint32_t> formats;
+#if ANDROID_VERSION_MAJOR==5
+    MediaCodecList::getInstance()->getCodecInfo(index)->getCapabilitiesFor(type)->getSupportedProfileLevels(&profile_levels);
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
+    status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &formats);
+#else
+    uint32_t flags;
+    status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &formats, &flags);
+#endif
+#if ANDROID_VERSION_MAJOR<5
+    if (err != OK)
+    {
+        ALOGE("Failed to get the nth codec profile level (err: %d)", err);
+        return 0;
+    }
+#endif
+
+    pro_level->profile = profile_levels[n].mProfile;
+    pro_level->level = profile_levels[n].mLevel;
+
+#if ANDROID_VERSION_MAJOR==5
+    return OK;
+#else
+    return err;
+#endif
+}
+
+int media_codec_list_get_codec_color_formats(size_t index, const char *type, uint32_t *color_formats)
+{
+    REPORT_FUNCTION()
+
+#if ANDROID_VERSION_MAJOR==5
+    Vector<MediaCodecInfo::ProfileLevel> profile_levels;
+#else
+    Vector<MediaCodecList::ProfileLevel> profile_levels;
+#endif
+    Vector<uint32_t> formats;
+#if ANDROID_VERSION_MAJOR==5
+    MediaCodecList::getInstance()->getCodecInfo(index)->getCapabilitiesFor(type)->getSupportedColorFormats(&formats);
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
+    status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &formats);
+#else
+    uint32_t flags;
+    status_t err = MediaCodecList::getInstance()->getCodecCapabilities(index, type, &profile_levels, &formats, &flags);
+#endif
+#if ANDROID_VERSION_MAJOR<5
+    if (err != OK)
+    {
+        ALOGE("Failed to get the number of supported codec types (err: %d)", err);
+        return 0;
+    }
+#endif
+
+    for (size_t i=0; i<formats.size(); ++i)
+    {
+        color_formats[i] = formats[i];
+        ALOGD("Color format [%d]: %d", i, formats[i]);
+    }
+
+    return OK;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_compatibility_layer.cpp
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ */
+
+// Uncomment to enable verbose debug output
+#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "MediaCompatibilityLayer"
+
+#include <hybris/media/media_compatibility_layer.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <media/mediaplayer.h>
+
+#include <binder/ProcessState.h>
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+#include <gui/SurfaceTexture.h>
+#else
+#include <gui/GLConsumer.h>
+#endif
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <utils/Log.h>
+
+#include <gui/NativeBufferAlloc.h>
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__)
+
+namespace android
+{
+NativeBufferAlloc::NativeBufferAlloc() {
+}
+
+NativeBufferAlloc::~NativeBufferAlloc() {
+}
+
+sp<GraphicBuffer> NativeBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h,
+			PixelFormat format, uint32_t usage, status_t* error) {
+	sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
+	status_t err = graphicBuffer->initCheck();
+	*error = err;
+	if (err != 0 || graphicBuffer->handle == 0) {
+		if (err == NO_MEMORY) {
+			GraphicBuffer::dumpAllocationsToSystemLog();
+		}
+		ALOGI("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "
+				"failed (%s), handle=%p",
+				w, h, strerror(-err), graphicBuffer->handle);
+		return 0;
+	}
+	return graphicBuffer;
+}
+}
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+struct FrameAvailableListener : public android::SurfaceTexture::FrameAvailableListener
+#else
+struct FrameAvailableListener : public android::GLConsumer::FrameAvailableListener
+#endif
+{
+	public:
+		FrameAvailableListener()
+			: set_video_texture_needs_update_cb(NULL),
+			video_texture_needs_update_context(NULL)
+		{
+		}
+
+		// From android::GLConsumer/SurfaceTexture::FrameAvailableListener
+#if ANDROID_VERSION_MAJOR==5 && ANDROID_VERSION_MINOR>=1
+		virtual void onFrameAvailable(const android::BufferItem& item)
+#else
+		virtual void onFrameAvailable()
+#endif
+		{
+			if (set_video_texture_needs_update_cb != NULL)
+				set_video_texture_needs_update_cb(video_texture_needs_update_context);
+		}
+
+		void setVideoTextureNeedsUpdateCb(on_video_texture_needs_update cb, void *context)
+		{
+			set_video_texture_needs_update_cb = cb;
+			video_texture_needs_update_context = context;
+		}
+
+	private:
+		on_video_texture_needs_update set_video_texture_needs_update_cb;
+		void *video_texture_needs_update_context;
+};
+
+class MediaPlayerListenerWrapper : public android::MediaPlayerListener
+{
+	public:
+		MediaPlayerListenerWrapper()
+			: set_video_size_cb(NULL),
+			video_size_context(NULL),
+			error_cb(NULL),
+			error_context(NULL),
+			playback_complete_cb(NULL),
+			playback_complete_context(NULL),
+			media_prepared_cb(NULL),
+			media_prepared_context(NULL)
+		{
+		}
+
+		void notify(int msg, int ext1, int ext2, const android::Parcel *obj)
+		{
+			ALOGV("\tmsg: %d, ext1: %d, ext2: %d \n", msg, ext1, ext2);
+
+			switch (msg) {
+			case android::MEDIA_PREPARED:
+				ALOGV("\tMEDIA_PREPARED msg\n");
+				if (media_prepared_cb != NULL)
+					media_prepared_cb(media_prepared_context);
+				else
+					ALOGW("Failed to signal media prepared, callback not set.");
+				break;
+			case android::MEDIA_PLAYBACK_COMPLETE:
+				ALOGV("\tMEDIA_PLAYBACK_COMPLETE msg\n");
+				if (playback_complete_cb != NULL)
+					playback_complete_cb(playback_complete_context);
+				else
+					ALOGW("Failed to signal end of playback, callback not set.");
+				break;
+			case android::MEDIA_BUFFERING_UPDATE:
+				ALOGV("\tMEDIA_BUFFERING_UPDATE msg\n");
+				break;
+			case android::MEDIA_SEEK_COMPLETE:
+				ALOGV("\tMEDIA_SEEK_COMPLETE msg\n");
+				break;
+			case android::MEDIA_SET_VIDEO_SIZE:
+				ALOGV("\tMEDIA_SET_VIDEO_SIZE msg\n");
+				if (set_video_size_cb != NULL)
+					set_video_size_cb(ext2, ext1, video_size_context);
+				else
+					ALOGE("Failed to set video size. set_video_size_cb is NULL.");
+				break;
+			case android::MEDIA_TIMED_TEXT:
+				ALOGV("\tMEDIA_TIMED_TEXT msg\n");
+				break;
+			case android::MEDIA_ERROR:
+				ALOGV("\tMEDIA_ERROR msg\n");
+				// TODO: Extend this cb to include the error message
+				if (error_cb != NULL)
+					error_cb(error_context);
+				else
+					ALOGE("Failed to signal error to app layer, callback not set.");
+				break;
+			case android::MEDIA_INFO:
+				ALOGV("\tMEDIA_INFO msg\n");
+				break;
+			default:
+				ALOGV("\tUnknown media msg\n");
+			}
+		}
+
+		void setVideoSizeCb(on_msg_set_video_size cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			set_video_size_cb = cb;
+			video_size_context = context;
+		}
+
+		void setErrorCb(on_msg_error cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			error_cb = cb;
+			error_context = context;
+		}
+
+		void setPlaybackCompleteCb(on_playback_complete cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			playback_complete_cb = cb;
+			playback_complete_context = context;
+		}
+
+		void setMediaPreparedCb(on_media_prepared cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			media_prepared_cb = cb;
+			media_prepared_context = context;
+		}
+
+	private:
+		on_msg_set_video_size set_video_size_cb;
+		void *video_size_context;
+		on_msg_error error_cb;
+		void *error_context;
+		on_playback_complete playback_complete_cb;
+		void *playback_complete_context;
+		on_media_prepared media_prepared_cb;
+		void *media_prepared_context;
+};
+
+// ----- MediaPlayer Wrapper ----- //
+
+struct MediaPlayerWrapper : public android::MediaPlayer
+{
+	public:
+		MediaPlayerWrapper()
+			: MediaPlayer(),
+			texture(NULL),
+			media_player_listener(new MediaPlayerListenerWrapper()),
+			frame_listener(new FrameAvailableListener),
+			left_volume(1), // Set vol to 100% for this track by default
+			right_volume(1),
+			source_fd(-1)
+		{
+			setListener(media_player_listener);
+			// Update the live volume with the cached values
+			MediaPlayer::setVolume(left_volume, right_volume);
+		}
+
+		~MediaPlayerWrapper()
+		{
+			reset();
+			source_fd = -1;
+		}
+
+#if  ANDROID_VERSION_MAJOR==5
+		android::status_t setVideoSurfaceTexture(android::sp<android::IGraphicBufferProducer> bq, const android::sp<android::GLConsumer> &surfaceTexture)
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+		android::status_t setVideoSurfaceTexture(const android::sp<android::SurfaceTexture> &surfaceTexture)
+#else
+		android::status_t setVideoSurfaceTexture(android::sp<android::BufferQueue> bq, const android::sp<android::GLConsumer> &surfaceTexture)
+#endif
+		{
+			REPORT_FUNCTION();
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+			surfaceTexture->getBufferQueue()->setBufferCount(5);
+#else
+			bq->setBufferCount(5);
+#endif
+			texture = surfaceTexture;
+			texture->setFrameAvailableListener(frame_listener);
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+			return MediaPlayer::setVideoSurfaceTexture(surfaceTexture->getBufferQueue());
+#else
+			return MediaPlayer::setVideoSurfaceTexture(bq);
+#endif
+		}
+
+		void updateGLConsumer()
+		{
+			assert(texture != NULL);
+			texture->updateTexImage();
+		}
+
+		void get_transformation_matrix_for_surface_texture(GLfloat* matrix)
+		{
+			assert(texture != NULL);
+			texture->getTransformMatrix(matrix);
+		}
+
+		void setVideoSizeCb(on_msg_set_video_size cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			assert(media_player_listener != NULL);
+			media_player_listener->setVideoSizeCb(cb, context);
+		}
+
+		void setVideoTextureNeedsUpdateCb(on_video_texture_needs_update cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			assert(frame_listener != NULL);
+			frame_listener->setVideoTextureNeedsUpdateCb(cb, context);
+		}
+
+		void setErrorCb(on_msg_error cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			assert(media_player_listener != NULL);
+			media_player_listener->setErrorCb(cb, context);
+		}
+
+		void setPlaybackCompleteCb(on_playback_complete cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			assert(media_player_listener != NULL);
+			media_player_listener->setPlaybackCompleteCb(cb, context);
+		}
+
+		void setMediaPreparedCb(on_media_prepared cb, void *context)
+		{
+			REPORT_FUNCTION();
+
+			assert(media_player_listener != NULL);
+			media_player_listener->setMediaPreparedCb(cb, context);
+		}
+
+		void getVolume(float *leftVolume, float *rightVolume)
+		{
+			*leftVolume = left_volume;
+			*rightVolume = right_volume;
+		}
+
+		android::status_t setVolume(float leftVolume, float rightVolume)
+		{
+			REPORT_FUNCTION();
+
+			left_volume = leftVolume;
+			right_volume = rightVolume;
+			return MediaPlayer::setVolume(leftVolume, rightVolume);
+		}
+
+		int getSourceFd() const { return source_fd; }
+		void setSourceFd(int fd) { source_fd = fd; }
+
+	private:
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+		android::sp<android::SurfaceTexture> texture;
+#else
+		android::sp<android::GLConsumer> texture;
+#endif
+		android::sp<MediaPlayerListenerWrapper> media_player_listener;
+		android::sp<FrameAvailableListener> frame_listener;
+		float left_volume;
+		float right_volume;
+		int source_fd;
+}; // MediaPlayerWrapper
+
+using namespace android;
+
+// ----- Media Player C API Implementation ----- //
+
+void android_media_set_video_size_cb(MediaPlayerWrapper *mp, on_msg_set_video_size cb, void *context)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return;
+	}
+
+	mp->setVideoSizeCb(cb, context);
+}
+
+void android_media_set_video_texture_needs_update_cb(MediaPlayerWrapper *mp, on_video_texture_needs_update cb, void *context)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return;
+	}
+
+	mp->setVideoTextureNeedsUpdateCb(cb, context);
+}
+
+void android_media_set_error_cb(MediaPlayerWrapper *mp, on_msg_error cb, void *context)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return;
+	}
+
+	mp->setErrorCb(cb, context);
+}
+
+void android_media_set_playback_complete_cb(MediaPlayerWrapper *mp, on_playback_complete cb, void *context)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return;
+	}
+
+	mp->setPlaybackCompleteCb(cb, context);
+}
+
+void android_media_set_media_prepared_cb(MediaPlayerWrapper *mp, on_media_prepared cb, void *context)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return;
+	}
+
+	mp->setMediaPreparedCb(cb, context);
+}
+
+MediaPlayerWrapper *android_media_new_player()
+{
+	REPORT_FUNCTION();
+
+	MediaPlayerWrapper *mp = new MediaPlayerWrapper();
+	if (mp == NULL) {
+		ALOGE("Failed to create new MediaPlayerWrapper instance.");
+		return NULL;
+	}
+
+	// Required for internal player state processing. Without this, prepare() and start() hang.
+	ProcessState::self()->startThreadPool();
+
+	return mp;
+}
+
+int android_media_set_data_source(MediaPlayerWrapper *mp, const char* url)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	if (url == NULL) {
+		ALOGE("url must not be NULL");
+		return BAD_VALUE;
+	}
+
+	ALOGD("url: %s", url);
+
+	String16 src(url);
+	if (src.startsWith(String16("http://")) == true) {
+		ALOGD("HTTP source URL detected");
+#if 0 // remarked for future debugging - chunsang
+#if ANDROID_VERSION_MAJOR==5
+		mp->setDataSource(NULL,url, NULL);
+#else
+		mp->setDataSource(url, NULL);
+#endif
+#endif
+	} else {
+		ALOGD("File source URL detected");
+		int fd = open(url, O_RDONLY);
+		if (fd < 0)
+		{
+			ALOGE("Failed to open source data at: %s\n", url);
+			return BAD_VALUE;
+		}
+
+		mp->setSourceFd(fd);
+
+		struct stat st;
+		stat(url, &st);
+
+		ALOGD("source file length: %lld\n", st.st_size);
+
+		mp->setDataSource(fd, 0, st.st_size);
+	}
+	mp->prepare();
+
+	return OK;
+}
+
+int android_media_set_preview_texture(MediaPlayerWrapper *mp, int texture_id)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	android::sp<android::NativeBufferAlloc> native_alloc(
+			new android::NativeBufferAlloc()
+			);
+
+#if ANDROID_VERSION_MAJOR==5
+	android::sp<IGraphicBufferProducer> producer;
+	android::sp<IGraphicBufferConsumer> consumer;
+	BufferQueue::createBufferQueue(&producer, &consumer);
+#else
+	android::sp<android::BufferQueue> buffer_queue(
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
+			new android::BufferQueue(false, NULL, native_alloc)
+#else
+			new android::BufferQueue(NULL)
+#endif
+			);
+#endif
+
+	static const bool allow_synchronous_mode = true;
+	// Create a new GLConsumer/SurfaceTexture from the texture_id in synchronous mode (don't wait on all data in the buffer)
+#if ANDROID_VERSION_MAJOR==5
+	mp->setVideoSurfaceTexture(producer, android::sp<android::GLConsumer>(
+				new android::GLConsumer(
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+	mp->setVideoSurfaceTexture(android::sp<android::SurfaceTexture>(
+				new android::SurfaceTexture(
+#else
+	mp->setVideoSurfaceTexture(buffer_queue, android::sp<android::GLConsumer>(
+				new android::GLConsumer(
+#endif
+#if ANDROID_VERSION_MAJOR==5
+					consumer,
+					texture_id,
+					GL_TEXTURE_EXTERNAL_OES,
+					true,
+					false)));
+
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
+					texture_id,
+					allow_synchronous_mode,
+					GL_TEXTURE_EXTERNAL_OES,
+					true,
+					buffer_queue)));
+#else
+					buffer_queue,
+					texture_id,
+					GL_TEXTURE_EXTERNAL_OES,
+					true,
+					false)));
+#endif
+
+	return OK;
+}
+
+void android_media_update_surface_texture(MediaPlayerWrapper *mp)
+{
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return;
+	}
+
+	mp->updateGLConsumer();
+}
+
+void android_media_surface_texture_get_transformation_matrix(MediaPlayerWrapper *mp, GLfloat* matrix)
+{
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return;
+	}
+
+	mp->get_transformation_matrix_for_surface_texture(matrix);
+}
+
+int android_media_play(MediaPlayerWrapper *mp)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	mp->start();
+	const char *tmp = mp->isPlaying() ? "yes" : "no";
+	ALOGV("Is playing?: %s\n", tmp);
+
+	return OK;
+}
+
+int android_media_pause(MediaPlayerWrapper *mp)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	mp->pause();
+
+	return OK;
+}
+
+int android_media_stop(MediaPlayerWrapper *mp)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	mp->stop();
+
+	int fd = mp->getSourceFd();
+	if (fd > -1)
+		close(fd);
+
+	return OK;
+}
+
+bool android_media_is_playing(MediaPlayerWrapper *mp)
+{
+	if (mp != NULL) {
+		if (mp->isPlaying())
+			return true;
+	}
+
+	return false;
+}
+
+int android_media_seek_to(MediaPlayerWrapper *mp, int msec)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	return mp->seekTo(msec);
+}
+
+int android_media_get_current_position(MediaPlayerWrapper *mp, int *msec)
+{
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	return mp->getCurrentPosition(msec);
+}
+
+int android_media_get_duration(MediaPlayerWrapper *mp, int *msec)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	return mp->getDuration(msec);
+}
+
+int android_media_get_volume(MediaPlayerWrapper *mp, int *volume)
+{
+	REPORT_FUNCTION();
+
+	if (volume == NULL) {
+		ALOGE("volume must not be NULL");
+		return BAD_VALUE;
+	}
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	float left_volume = 0, right_volume = 0;
+	mp->getVolume(&left_volume, &right_volume);
+	*volume = left_volume * 100;
+
+	return OK;
+}
+
+int android_media_set_volume(MediaPlayerWrapper *mp, int volume)
+{
+	REPORT_FUNCTION();
+
+	if (mp == NULL) {
+		ALOGE("mp must not be NULL");
+		return BAD_VALUE;
+	}
+
+	float left_volume = float(volume / 100);
+	float right_volume = float(volume / 100);
+	return mp->setVolume(left_volume, right_volume);
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_format_layer.cpp
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+// Uncomment to enable verbose debug output
+#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "MediaFormatLayer"
+
+#include <hybris/media/media_format_layer.h>
+#include "media_format_layer_priv.h"
+
+#include <assert.h>
+
+#include <utils/Log.h>
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__);
+
+using namespace android;
+
+static inline _MediaFormat *get_internal_format(MediaFormat format)
+{
+    if (format == NULL)
+    {
+        ALOGE("format must not be NULL");
+        return NULL;
+    }
+
+    _MediaFormat *mf = static_cast<_MediaFormat*>(format);
+    assert(mf->refcount >= 1);
+
+    return mf;
+}
+
+MediaFormat media_format_create_video_format(const char *mime, int32_t width, int32_t height, int64_t duration_us, int32_t max_input_size)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *format = new _MediaFormat();
+    format->mime = AString(mime);
+    format->width = width;
+    format->height = height;
+    format->duration_us = duration_us;
+    format->max_input_size = max_input_size;
+
+    return format;
+}
+
+void media_format_destroy(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return;
+
+    if (mf->refcount)
+        return;
+
+    delete mf;
+}
+
+void media_format_ref(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return;
+
+    mf->refcount++;
+}
+
+void media_format_unref(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return;
+
+    if (mf->refcount)
+        mf->refcount--;
+}
+
+void media_format_set_byte_buffer(MediaFormat format, const char *key, uint8_t *data, size_t size)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return;
+    if (key == NULL || data == NULL || size == 0)
+        return;
+
+    mf->csd_key_name = AString(key);
+    mf->csd = sp<ABuffer>(new ABuffer(data, size));
+}
+
+const char* media_format_get_mime(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return NULL;
+
+    return mf->mime.c_str();
+}
+
+int64_t media_format_get_duration_us(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->duration_us;
+}
+
+int32_t media_format_get_width(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->width;
+}
+
+int32_t media_format_get_height(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->height;
+}
+
+int32_t media_format_get_max_input_size(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->max_input_size;
+}
+
+int32_t media_format_get_stride(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->stride;
+}
+
+int32_t media_format_get_slice_height(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->slice_height;
+}
+
+int32_t media_format_get_color_format(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->color_format;
+}
+
+int32_t media_format_get_crop_left(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->crop_left;
+}
+
+int32_t media_format_get_crop_right(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->crop_right;
+}
+
+int32_t media_format_get_crop_top(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->crop_top;
+}
+
+int32_t media_format_get_crop_bottom(MediaFormat format)
+{
+    REPORT_FUNCTION()
+
+    _MediaFormat *mf = get_internal_format(format);
+    if (mf == NULL)
+        return 0;
+
+    return mf->crop_bottom;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_format_layer_priv.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#include <stddef.h>
+#include <unistd.h>
+
+#include <media/stagefright/foundation/AString.h>
+
+#include <utils/RefBase.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _MediaFormat : public RefBase
+{
+    _MediaFormat()
+      : refcount(1)
+    {
+    }
+
+    AString mime;
+    int64_t duration_us;
+    int32_t width;
+    int32_t height;
+    int32_t max_input_size;
+
+    unsigned int refcount;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_format_layer_priv.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef MEDIA_FORMAT_LAYER_PRIV_H_
+#define MEDIA_FORMAT_LAYER_PRIV_H_
+
+#include <stddef.h>
+#include <unistd.h>
+
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/ABuffer.h>
+
+#include <utils/RefBase.h>
+
+struct _MediaFormat : public android::RefBase
+{
+    _MediaFormat()
+      : duration_us(0),
+        width(0),
+        height(0),
+        max_input_size(0),
+        csd(NULL),
+        stride(0),
+        slice_height(0),
+        color_format(0),
+        crop_left(0),
+        crop_right(0),
+        crop_top(0),
+        crop_bottom(0),
+        refcount(1)
+    {
+    }
+
+    android::AString mime;
+    int64_t duration_us;
+    int32_t width;
+    int32_t height;
+    int32_t max_input_size;
+    android::AString csd_key_name;
+    android::sp<android::ABuffer> csd;
+
+    int32_t stride;
+    int32_t slice_height;
+    int32_t color_format;
+    int32_t crop_left;
+    int32_t crop_right;
+    int32_t crop_top;
+    int32_t crop_bottom;
+
+    unsigned int refcount;
+};
+
+#endif // MEDIA_FORMAT_LAYER_PRIV_H_
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder.cpp
@@ -0,0 +1,747 @@
+/*
+ ** Copyright (c) 2008 The Android Open Source Project
+ ** Copyright (C) 2014 Canonical Ltd
+ **
+ ** Adapted from the Android equivalent code for use in Ubuntu.
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "MediaRecorder"
+
+#include "media_recorder.h"
+#include "media_recorder_factory.h"
+
+#include <utils/Log.h>
+#include <binder/IServiceManager.h>
+#include <utils/String8.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IMediaRecorder.h>
+#include <media/mediaplayer.h>  // for MEDIA_ERROR_SERVER_DIED
+#include <gui/IGraphicBufferProducer.h>
+
+namespace android {
+
+status_t MediaRecorder::setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy)
+{
+    ALOGV("setCamera(%p,%p)", camera.get(), proxy.get());
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_IDLE)) {
+        ALOGE("setCamera called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setCamera(camera, proxy);
+    if (OK != ret) {
+        ALOGV("setCamera failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::setPreviewSurface(const sp<IGraphicBufferProducer>& surface)
+{
+    ALOGV("setPreviewSurface(%p)", surface.get());
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("setPreviewSurface called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (!mIsVideoSourceSet) {
+        ALOGE("try to set preview surface without setting the video source first");
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setPreviewSurface(surface);
+    if (OK != ret) {
+        ALOGV("setPreviewSurface failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::init()
+{
+    ALOGV("init");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_IDLE)) {
+        ALOGE("init called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->init();
+    if (OK != ret) {
+        ALOGV("init failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+
+    ret = mMediaRecorder->setListener(this);
+    if (OK != ret) {
+        ALOGV("setListener failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+
+    mCurrentState = MEDIA_RECORDER_INITIALIZED;
+    return ret;
+}
+
+status_t MediaRecorder::setVideoSource(int vs)
+{
+    ALOGV("setVideoSource(%d)", vs);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mIsVideoSourceSet) {
+        ALOGE("video source has already been set");
+        return INVALID_OPERATION;
+    }
+    if (mCurrentState & MEDIA_RECORDER_IDLE) {
+        ALOGV("Call init() since the media recorder is not initialized yet");
+        status_t ret = init();
+        if (OK != ret) {
+            return ret;
+        }
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        ALOGE("setVideoSource called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    // following call is made over the Binder Interface
+    status_t ret = mMediaRecorder->setVideoSource(vs);
+
+    if (OK != ret) {
+        ALOGV("setVideoSource failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mIsVideoSourceSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setAudioSource(int as)
+{
+    ALOGV("setAudioSource(%d)", as);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mCurrentState & MEDIA_RECORDER_IDLE) {
+        ALOGV("Call init() since the media recorder is not initialized yet");
+        status_t ret = init();
+        if (OK != ret) {
+            return ret;
+        }
+    }
+    if (mIsAudioSourceSet) {
+        ALOGE("audio source has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        ALOGE("setAudioSource called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setAudioSource(as);
+    if (OK != ret) {
+        ALOGV("setAudioSource failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mIsAudioSourceSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setOutputFormat(int of)
+{
+    ALOGV("setOutputFormat(%d)", of);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        ALOGE("setOutputFormat called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (mIsVideoSourceSet && of >= OUTPUT_FORMAT_AUDIO_ONLY_START && of != OUTPUT_FORMAT_RTP_AVP && of != OUTPUT_FORMAT_MPEG2TS) { //first non-video output format
+        ALOGE("output format (%d) is meant for audio recording only and incompatible with video recording", of);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setOutputFormat(of);
+    if (OK != ret) {
+        ALOGE("setOutputFormat failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mCurrentState = MEDIA_RECORDER_DATASOURCE_CONFIGURED;
+    return ret;
+}
+
+status_t MediaRecorder::setVideoEncoder(int ve)
+{
+    ALOGV("setVideoEncoder(%d)", ve);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!mIsVideoSourceSet) {
+        ALOGE("try to set the video encoder without setting the video source first");
+        return INVALID_OPERATION;
+    }
+    if (mIsVideoEncoderSet) {
+        ALOGE("video encoder has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("setVideoEncoder called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setVideoEncoder(ve);
+    if (OK != ret) {
+        ALOGV("setVideoEncoder failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mIsVideoEncoderSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setAudioEncoder(int ae)
+{
+    ALOGV("setAudioEncoder(%d)", ae);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!mIsAudioSourceSet) {
+        ALOGE("try to set the audio encoder without setting the audio source first");
+        return INVALID_OPERATION;
+    }
+    if (mIsAudioEncoderSet) {
+        ALOGE("audio encoder has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("setAudioEncoder called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setAudioEncoder(ae);
+    if (OK != ret) {
+        ALOGV("setAudioEncoder failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mIsAudioEncoderSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setOutputFile(const char* path)
+{
+    ALOGV("setOutputFile(%s)", path);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mIsOutputFileSet) {
+        ALOGE("output file has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("setOutputFile called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setOutputFile(path);
+    if (OK != ret) {
+        ALOGV("setOutputFile failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mIsOutputFileSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setOutputFile(int fd, int64_t offset, int64_t length)
+{
+    ALOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mIsOutputFileSet) {
+        ALOGE("output file has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("setOutputFile called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    // It appears that if an invalid file descriptor is passed through
+    // binder calls, the server-side of the inter-process function call
+    // is skipped. As a result, the check at the server-side to catch
+    // the invalid file descritpor never gets invoked. This is to workaround
+    // this issue by checking the file descriptor first before passing
+    // it through binder call.
+    if (fd < 0) {
+        ALOGE("Invalid file descriptor: %d", fd);
+        return BAD_VALUE;
+    }
+
+    status_t ret = mMediaRecorder->setOutputFile(fd, offset, length);
+    if (OK != ret) {
+        ALOGV("setOutputFile failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mIsOutputFileSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setVideoSize(int width, int height)
+{
+    ALOGV("setVideoSize(%d, %d)", width, height);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("setVideoSize called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (!mIsVideoSourceSet) {
+        ALOGE("Cannot set video size without setting video source first");
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setVideoSize(width, height);
+    if (OK != ret) {
+        ALOGE("setVideoSize failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+
+    return ret;
+}
+
+// Query a SurfaceMediaSurface through the Mediaserver, over the
+// binder interface. This is used by the Filter Framework (MediaEncoder)
+// to get an <IGraphicBufferProducer> object to hook up to ANativeWindow.
+sp<IGraphicBufferProducer> MediaRecorder::
+        querySurfaceMediaSourceFromMediaServer()
+{
+    Mutex::Autolock _l(mLock);
+    mSurfaceMediaSource =
+            mMediaRecorder->querySurfaceMediaSource();
+    if (mSurfaceMediaSource == NULL) {
+        ALOGE("SurfaceMediaSource could not be initialized!");
+    }
+    return mSurfaceMediaSource;
+}
+
+status_t MediaRecorder::setVideoFrameRate(int frames_per_second)
+{
+    ALOGV("setVideoFrameRate(%d)", frames_per_second);
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("setVideoFrameRate called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (!mIsVideoSourceSet) {
+        ALOGE("Cannot set video frame rate without setting video source first");
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setVideoFrameRate(frames_per_second);
+    if (OK != ret) {
+        ALOGE("setVideoFrameRate failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::setParameters(const String8& params) {
+    ALOGV("setParameters(%s)", params.string());
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+
+    bool isInvalidState = (mCurrentState &
+                           (MEDIA_RECORDER_PREPARED |
+                            MEDIA_RECORDER_RECORDING |
+                            MEDIA_RECORDER_ERROR));
+    if (isInvalidState) {
+        ALOGE("setParameters is called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setParameters(params);
+    if (OK != ret) {
+        ALOGE("setParameters(%s) failed: %d", params.string(), ret);
+        // Do not change our current state to MEDIA_RECORDER_ERROR, failures
+        // of the only currently supported parameters, "max-duration" and
+        // "max-filesize" are _not_ fatal.
+    }
+
+    return ret;
+}
+
+status_t MediaRecorder::prepare()
+{
+    ALOGV("prepare");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        ALOGE("prepare called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (mIsAudioSourceSet != mIsAudioEncoderSet) {
+        if (mIsAudioSourceSet) {
+            ALOGE("audio source is set, but audio encoder is not set");
+        } else {  // must not happen, since setAudioEncoder checks this already
+            ALOGE("audio encoder is set, but audio source is not set");
+        }
+        return INVALID_OPERATION;
+    }
+
+    if (mIsVideoSourceSet != mIsVideoEncoderSet) {
+        if (mIsVideoSourceSet) {
+            ALOGE("video source is set, but video encoder is not set");
+        } else {  // must not happen, since setVideoEncoder checks this already
+            ALOGE("video encoder is set, but video source is not set");
+        }
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->prepare();
+    if (OK != ret) {
+        ALOGE("prepare failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mCurrentState = MEDIA_RECORDER_PREPARED;
+    return ret;
+}
+
+status_t MediaRecorder::getMaxAmplitude(int* max)
+{
+    ALOGV("getMaxAmplitude");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mCurrentState & MEDIA_RECORDER_ERROR) {
+        ALOGE("getMaxAmplitude called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->getMaxAmplitude(max);
+    if (OK != ret) {
+        ALOGE("getMaxAmplitude failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::start()
+{
+    ALOGV("start");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_PREPARED)) {
+        ALOGE("start called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->start();
+    if (OK != ret) {
+        ALOGE("start failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+    mCurrentState = MEDIA_RECORDER_RECORDING;
+    return ret;
+}
+
+status_t MediaRecorder::stop()
+{
+    ALOGV("stop");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_RECORDING)) {
+        ALOGE("stop called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->stop();
+    if (OK != ret) {
+        ALOGE("stop failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+
+    // FIXME:
+    // stop and reset are semantically different.
+    // We treat them the same for now, and will change this in the future.
+    doCleanUp();
+    mCurrentState = MEDIA_RECORDER_IDLE;
+    return ret;
+}
+
+// Reset should be OK in any state
+status_t MediaRecorder::reset()
+{
+    ALOGV("reset");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+
+    doCleanUp();
+    status_t ret = UNKNOWN_ERROR;
+    switch (mCurrentState) {
+        case MEDIA_RECORDER_IDLE:
+            ret = OK;
+            break;
+
+        case MEDIA_RECORDER_RECORDING:
+        case MEDIA_RECORDER_DATASOURCE_CONFIGURED:
+        case MEDIA_RECORDER_PREPARED:
+        case MEDIA_RECORDER_ERROR: {
+            ret = doReset();
+            if (OK != ret) {
+                return ret;  // No need to continue
+            }
+        }  // Intentional fall through
+        case MEDIA_RECORDER_INITIALIZED:
+            ret = close();
+            break;
+
+        default: {
+            ALOGE("Unexpected non-existing state: %d", mCurrentState);
+            break;
+        }
+    }
+    return ret;
+}
+
+status_t MediaRecorder::close()
+{
+    ALOGV("close");
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        ALOGE("close called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    status_t ret = mMediaRecorder->close();
+    if (OK != ret) {
+        ALOGE("close failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    } else {
+        mCurrentState = MEDIA_RECORDER_IDLE;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::doReset()
+{
+    ALOGV("doReset");
+    status_t ret = mMediaRecorder->reset();
+    if (OK != ret) {
+        ALOGE("doReset failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    } else {
+        mCurrentState = MEDIA_RECORDER_INITIALIZED;
+    }
+    return ret;
+}
+
+void MediaRecorder::doCleanUp()
+{
+    ALOGV("doCleanUp");
+    mIsAudioSourceSet  = false;
+    mIsVideoSourceSet  = false;
+    mIsAudioEncoderSet = false;
+    mIsVideoEncoderSet = false;
+    mIsOutputFileSet   = false;
+}
+
+// Release should be OK in any state
+status_t MediaRecorder::release()
+{
+    ALOGV("release");
+    if (mMediaRecorder != NULL) {
+        return mMediaRecorder->release();
+    }
+    return INVALID_OPERATION;
+}
+
+
+MediaRecorder::MediaRecorder()
+    : mMediaRecorderFactory(NULL),
+    mSurfaceMediaSource(NULL)
+{
+    ALOGV("constructor (custom)");
+
+    if (mMediaRecorderFactory == NULL) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder;
+        do {
+            binder = sm->getService(String16(IMediaRecorderFactory::exported_service_name()));
+            if (binder != 0) {
+                break;
+            }
+            ALOGW("MediaRecorderFactory service not published, waiting...");
+            usleep(500000); // 0.5 s
+        } while (true);
+
+        mMediaRecorderFactory = interface_cast<IMediaRecorderFactory>(binder);
+    }
+
+    ALOGE_IF(mMediaRecorderFactory == NULL, "no MediaRecorderFactory!?");
+
+    mMediaRecorder = mMediaRecorderFactory->createMediaRecorder();
+    if (mMediaRecorder != NULL) {
+        mCurrentState = MEDIA_RECORDER_IDLE;
+    }
+
+    doCleanUp();
+}
+
+status_t MediaRecorder::initCheck()
+{
+    return mMediaRecorder != 0 ? NO_ERROR : NO_INIT;
+}
+
+MediaRecorder::~MediaRecorder()
+{
+    ALOGV("destructor");
+    if (mMediaRecorder != NULL) {
+        mMediaRecorder.clear();
+    }
+
+    if (mSurfaceMediaSource != NULL) {
+        mSurfaceMediaSource.clear();
+    }
+}
+
+status_t MediaRecorder::setListener(const sp<MediaRecorderListener>& listener)
+{
+    ALOGV("setListener");
+    Mutex::Autolock _l(mLock);
+    mListener = listener;
+
+    if (mMediaRecorder != NULL) {
+        // Sets a listener so that when the named pipe reader in RecordThread is ready,
+        // we can bubble up to media_recorder_layer to signal the app that it's ready
+        // to do audio recording
+        mMediaRecorder->setListener(this);
+    }
+
+    return NO_ERROR;
+}
+
+status_t MediaRecorder::setClientName(const String16& clientName)
+{
+    ALOGV("setClientName");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    bool isInvalidState = (mCurrentState &
+                           (MEDIA_RECORDER_PREPARED |
+                            MEDIA_RECORDER_RECORDING |
+                            MEDIA_RECORDER_ERROR));
+    if (isInvalidState) {
+        ALOGE("setClientName is called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    mMediaRecorder->setClientName(clientName);
+
+    return NO_ERROR;
+}
+
+void MediaRecorder::notify(int msg, int ext1, int ext2)
+{
+    ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
+
+    sp<MediaRecorderListener> listener;
+    mLock.lock();
+    listener = mListener;
+    mLock.unlock();
+
+    if (listener != NULL) {
+        Mutex::Autolock _l(mNotifyLock);
+        ALOGV("callback application");
+        listener->notify(msg, ext1, ext2);
+        ALOGV("back from callback");
+    }
+}
+
+void MediaRecorder::readAudio()
+{
+    ALOGV("%s", __PRETTY_FUNCTION__);
+
+    sp<MediaRecorderListener> listener;
+    status_t ret = NO_ERROR;
+    mLock.lock();
+    listener = mListener;
+    mLock.unlock();
+
+    if (listener != NULL) {
+        Mutex::Autolock _l(mReadAudioLock);
+        ALOGV("callback application");
+        listener->readAudio();
+        ALOGV("back from callback");
+    }
+}
+
+void MediaRecorder::died()
+{
+    ALOGV("died");
+    notify(MEDIA_RECORDER_EVENT_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
+}
+
+} // namespace android
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder.h
@@ -0,0 +1,269 @@
+/*
+ ** Copyright (C) 2008 The Android Open Source Project
+ ** Copyright (C) 2014 Canonical Ltd
+ **
+ ** Adapted from the Android equivalent code for use in Ubuntu.
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ **
+ ** limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIARECORDER_H
+#define ANDROID_MEDIARECORDER_H
+
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
+#include <media/IMediaRecorderClient.h>
+#include <media/IMediaDeathNotifier.h>
+#include <media/IMediaRecorder.h>
+
+namespace android {
+
+class Surface;
+class IMediaRecorder;
+class IMediaRecorderFactory;
+class ICamera;
+class ICameraRecordingProxy;
+class IGraphicBufferProducer;
+class Surface;
+
+typedef void (*media_completion_f)(status_t status, void *cookie);
+
+enum video_source {
+    VIDEO_SOURCE_DEFAULT = 0,
+    VIDEO_SOURCE_CAMERA = 1,
+    VIDEO_SOURCE_GRALLOC_BUFFER = 2,
+
+    VIDEO_SOURCE_LIST_END  // must be last - used to validate audio source type
+};
+
+// Please update media/java/android/media/MediaRecorder.java if the following is updated.
+enum output_format {
+    OUTPUT_FORMAT_DEFAULT = 0,
+    OUTPUT_FORMAT_THREE_GPP = 1,
+    OUTPUT_FORMAT_MPEG_4 = 2,
+
+
+    OUTPUT_FORMAT_AUDIO_ONLY_START = 3, // Used in validating the output format.  Should be the
+                                        //  at the start of the audio only output formats.
+
+    /* These are audio only file formats */
+    OUTPUT_FORMAT_RAW_AMR = 3, //to be backward compatible
+    OUTPUT_FORMAT_AMR_NB = 3,
+    OUTPUT_FORMAT_AMR_WB = 4,
+    OUTPUT_FORMAT_AAC_ADIF = 5,
+    OUTPUT_FORMAT_AAC_ADTS = 6,
+
+    /* Stream over a socket, limited to a single stream */
+    OUTPUT_FORMAT_RTP_AVP = 7,
+
+    /* H.264/AAC data encapsulated in MPEG2/TS */
+    OUTPUT_FORMAT_MPEG2TS = 8,
+
+    OUTPUT_FORMAT_LIST_END // must be last - used to validate format type
+};
+
+enum audio_encoder {
+    AUDIO_ENCODER_DEFAULT = 0,
+    AUDIO_ENCODER_AMR_NB = 1,
+    AUDIO_ENCODER_AMR_WB = 2,
+    AUDIO_ENCODER_AAC = 3,
+    AUDIO_ENCODER_HE_AAC = 4,
+    AUDIO_ENCODER_AAC_ELD = 5,
+
+    AUDIO_ENCODER_LIST_END // must be the last - used to validate the audio encoder type
+};
+
+enum video_encoder {
+    VIDEO_ENCODER_DEFAULT = 0,
+    VIDEO_ENCODER_H263 = 1,
+    VIDEO_ENCODER_H264 = 2,
+    VIDEO_ENCODER_MPEG_4_SP = 3,
+
+    VIDEO_ENCODER_LIST_END // must be the last - used to validate the video encoder type
+};
+
+/*
+ * The state machine of the media_recorder.
+ */
+enum media_recorder_states {
+    // Error state.
+    MEDIA_RECORDER_ERROR                 =      0,
+
+    // Recorder was just created.
+    MEDIA_RECORDER_IDLE                  = 1 << 0,
+
+    // Recorder has been initialized.
+    MEDIA_RECORDER_INITIALIZED           = 1 << 1,
+
+    // Configuration of the recorder has been completed.
+    MEDIA_RECORDER_DATASOURCE_CONFIGURED = 1 << 2,
+
+    // Recorder is ready to start.
+    MEDIA_RECORDER_PREPARED              = 1 << 3,
+
+    // Recording is in progress.
+    MEDIA_RECORDER_RECORDING             = 1 << 4,
+};
+
+// The "msg" code passed to the listener in notify.
+enum media_recorder_event_type {
+    MEDIA_RECORDER_EVENT_LIST_START               = 1,
+    MEDIA_RECORDER_EVENT_ERROR                    = 1,
+    MEDIA_RECORDER_EVENT_INFO                     = 2,
+    MEDIA_RECORDER_EVENT_LIST_END                 = 99,
+
+    // Track related event types
+    MEDIA_RECORDER_TRACK_EVENT_LIST_START         = 100,
+    MEDIA_RECORDER_TRACK_EVENT_ERROR              = 100,
+    MEDIA_RECORDER_TRACK_EVENT_INFO               = 101,
+    MEDIA_RECORDER_TRACK_EVENT_LIST_END           = 1000,
+};
+
+/*
+ * The (part of) "what" code passed to the listener in notify.
+ * When the error or info type is track specific, the what has
+ * the following layout:
+ * the left-most 16-bit is meant for error or info type.
+ * the right-most 4-bit is meant for track id.
+ * the rest is reserved.
+ *
+ * | track id | reserved |     error or info type     |
+ * 31         28         16                           0
+ *
+ */
+enum media_recorder_error_type {
+    MEDIA_RECORDER_ERROR_UNKNOWN                   = 1,
+
+    // Track related error type
+    MEDIA_RECORDER_TRACK_ERROR_LIST_START          = 100,
+    MEDIA_RECORDER_TRACK_ERROR_GENERAL             = 100,
+    MEDIA_RECORDER_ERROR_VIDEO_NO_SYNC_FRAME       = 200,
+    MEDIA_RECORDER_TRACK_ERROR_LIST_END            = 1000,
+};
+
+// The codes are distributed as follow:
+//   0xx: Reserved
+//   8xx: General info/warning
+//
+enum media_recorder_info_type {
+    MEDIA_RECORDER_INFO_UNKNOWN                   = 1,
+
+    MEDIA_RECORDER_INFO_MAX_DURATION_REACHED      = 800,
+    MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED      = 801,
+
+    // All track related informtional events start here
+    MEDIA_RECORDER_TRACK_INFO_LIST_START           = 1000,
+    MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS    = 1000,
+    MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME     = 1001,
+    MEDIA_RECORDER_TRACK_INFO_TYPE                 = 1002,
+    MEDIA_RECORDER_TRACK_INFO_DURATION_MS          = 1003,
+
+    // The time to measure the max chunk duration
+    MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS     = 1004,
+
+    MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES       = 1005,
+
+    // The time to measure how well the audio and video
+    // track data is interleaved.
+    MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS       = 1006,
+
+    // The time to measure system response. Note that
+    // the delay does not include the intentional delay
+    // we use to eliminate the recording sound.
+    MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS     = 1007,
+
+    // The time used to compensate for initial A/V sync.
+    MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS      = 1008,
+
+    // Total number of bytes of the media data.
+    MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES          = 1009,
+
+    MEDIA_RECORDER_TRACK_INFO_LIST_END             = 2000,
+};
+
+class MediaPlayerService;
+
+// ----------------------------------------------------------------------------
+// ref-counted object for callbacks
+class MediaRecorderListener: virtual public RefBase
+{
+public:
+    virtual void notify(int msg, int ext1, int ext2) = 0;
+    virtual void readAudio() = 0;
+};
+
+class MediaRecorder : public BnMediaRecorderClient,
+                      public virtual IMediaDeathNotifier
+{
+public:
+    MediaRecorder();
+    ~MediaRecorder();
+
+    void        died();
+    status_t    initCheck();
+    status_t    setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy);
+    status_t    setPreviewSurface(const sp<IGraphicBufferProducer>& surface);
+    status_t    setVideoSource(int vs);
+    status_t    setAudioSource(int as);
+    status_t    setOutputFormat(int of);
+    status_t    setVideoEncoder(int ve);
+    status_t    setAudioEncoder(int ae);
+    status_t    setOutputFile(const char* path);
+    status_t    setOutputFile(int fd, int64_t offset, int64_t length);
+    status_t    setVideoSize(int width, int height);
+    status_t    setVideoFrameRate(int frames_per_second);
+    status_t    setParameters(const String8& params);
+    status_t    setListener(const sp<MediaRecorderListener>& listener);
+    status_t    setClientName(const String16& clientName);
+    status_t    prepare();
+    status_t    getMaxAmplitude(int* max);
+    status_t    start();
+    status_t    stop();
+    status_t    reset();
+    status_t    init();
+    status_t    close();
+    status_t    release();
+    void        notify(int msg, int ext1, int ext2);
+    void        readAudio();
+    sp<IGraphicBufferProducer>     querySurfaceMediaSourceFromMediaServer();
+
+private:
+    void                    doCleanUp();
+    status_t                doReset();
+
+    sp<IMediaRecorder>          mMediaRecorder;
+    sp<MediaRecorderListener>   mListener;
+    sp<IMediaRecorderFactory>   mMediaRecorderFactory;
+
+    // Reference to IGraphicBufferProducer
+    // for encoding GL Frames. That is useful only when the
+    // video source is set to VIDEO_SOURCE_GRALLOC_BUFFER
+    sp<IGraphicBufferProducer>  mSurfaceMediaSource;
+
+    media_recorder_states       mCurrentState;
+    bool                        mIsAudioSourceSet;
+    bool                        mIsVideoSourceSet;
+    bool                        mIsAudioEncoderSet;
+    bool                        mIsVideoEncoderSet;
+    bool                        mIsOutputFileSet;
+    Mutex                       mLock;
+    Mutex                       mNotifyLock;
+    Mutex                       mReadAudioLock;
+};
+
+};  // namespace android
+
+#endif // ANDROID_MEDIARECORDER_H
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder_client.cpp
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2013-2014 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#include "media_recorder_client.h"
+
+#include <libmediaplayerservice/StagefrightRecorder.h>
+#include <binder/IServiceManager.h>
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "MediaRecorderClient"
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__)
+
+using namespace android;
+
+MediaRecorderClient::MediaRecorderClient()
+{
+    REPORT_FUNCTION();
+
+    sp<IServiceManager> service_manager = defaultServiceManager();
+    sp<IBinder> service = service_manager->getService(
+        String16(IMediaRecorderObserver::exported_service_name()));
+
+    media_recorder_observer = new BpMediaRecorderObserver(service);
+
+    recorder = new android::StagefrightRecorder;
+}
+
+MediaRecorderClient::~MediaRecorderClient()
+{
+    REPORT_FUNCTION();
+    release();
+}
+
+status_t MediaRecorderClient::setCamera(const sp<android::ICamera>& camera,
+        const sp<ICameraRecordingProxy>& proxy)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setCamera(camera, proxy);
+}
+
+status_t MediaRecorderClient::setPreviewSurface(const android::sp<android::IGraphicBufferProducer>& surface)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setPreviewSurface(surface);
+}
+
+status_t MediaRecorderClient::setVideoSource(int vs)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL)     {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setVideoSource((android::video_source)vs);
+}
+
+status_t MediaRecorderClient::setAudioSource(int as)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL)  {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setAudioSource((audio_source_t)as);
+}
+
+status_t MediaRecorderClient::setOutputFormat(int of)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setOutputFormat((android::output_format)of);
+}
+
+status_t MediaRecorderClient::setVideoEncoder(int ve)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setVideoEncoder((android::video_encoder)ve);
+}
+
+status_t MediaRecorderClient::setAudioEncoder(int ae)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setAudioEncoder((android::audio_encoder)ae);
+}
+
+status_t MediaRecorderClient::setOutputFile(const char* path)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setOutputFile(path);
+}
+
+status_t MediaRecorderClient::setOutputFile(int fd, int64_t offset, int64_t length)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setOutputFile(fd, offset, length);
+}
+
+status_t MediaRecorderClient::setVideoSize(int width, int height)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setVideoSize(width, height);
+}
+
+status_t MediaRecorderClient::setVideoFrameRate(int frames_per_second)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setVideoFrameRate(frames_per_second);
+}
+
+status_t MediaRecorderClient::setParameters(const android::String8& params)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setParameters(params);
+}
+
+status_t MediaRecorderClient::setListener(const android::sp<android::IMediaRecorderClient>& listener)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setListener(listener);
+}
+
+status_t MediaRecorderClient::setClientName(const android::String16& clientName)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->setClientName(clientName);
+}
+
+status_t MediaRecorderClient::prepare()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->prepare();
+}
+
+status_t MediaRecorderClient::getMaxAmplitude(int* max)
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->getMaxAmplitude(max);
+}
+
+status_t MediaRecorderClient::start()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+
+    if (media_recorder_observer != NULL)
+        media_recorder_observer->recordingStarted();
+
+    return recorder->start();
+}
+
+status_t MediaRecorderClient::stop()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+
+    if (media_recorder_observer != NULL)
+        media_recorder_observer->recordingStopped();
+
+    return recorder->stop();
+}
+
+#ifdef BOARD_HAS_MEDIA_RECORDER_PAUSE
+status_t MediaRecorderClient::pause()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->pause();
+
+}
+#endif
+
+#ifdef BOARD_HAS_MEDIA_RECORDER_RESUME
+status_t MediaRecorderClient::resume()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->resume();
+}
+#endif
+
+status_t MediaRecorderClient::reset()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->reset();
+}
+
+status_t MediaRecorderClient::init()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->init();
+}
+
+status_t MediaRecorderClient::close()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder must not be NULL");
+        return NO_INIT;
+    }
+    return recorder->close();
+}
+
+status_t MediaRecorderClient::release()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder != NULL) {
+        delete recorder;
+        recorder = NULL;
+    }
+    return NO_ERROR;
+}
+
+status_t MediaRecorderClient::dump(int fd, const Vector<String16>& args) const
+{
+    REPORT_FUNCTION();
+    if (recorder != NULL) {
+        return recorder->dump(fd, args);
+    }
+    return android::OK;
+}
+
+sp<IGraphicBufferProducer> MediaRecorderClient::querySurfaceMediaSource()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock lock(recorder_lock);
+    if (recorder == NULL) {
+        ALOGE("recorder is not initialized");
+        return NULL;
+    }
+    return recorder->querySurfaceMediaSource();
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder_client.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2013-2014 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef MEDIA_RECORDER_CLIENT_H_
+#define MEDIA_RECORDER_CLIENT_H_
+
+#include <hybris/internal/camera_control.h>
+#include <hybris/media/media_recorder_layer.h>
+
+#include "media_recorder_observer.h"
+
+#include <media/IMediaRecorder.h>
+
+namespace android {
+
+class MediaRecorderBase;
+class Mutex;
+class BpMediaRecorderObserver;
+
+/*!
+ * \brief The MediaRecorderClient struct wraps the service side of the MediaRecorder class
+ */
+struct MediaRecorderClient : public BnMediaRecorder
+{
+public:
+    MediaRecorderClient();
+    virtual ~MediaRecorderClient();
+
+    virtual status_t setCamera(const sp<ICamera>& camera,
+            const sp<ICameraRecordingProxy>& proxy);
+    virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface);
+    virtual status_t setVideoSource(int vs);
+    virtual status_t setAudioSource(int as);
+    virtual status_t setOutputFormat(int of);
+    virtual status_t setVideoEncoder(int ve);
+    virtual status_t setAudioEncoder(int ae);
+    virtual status_t setOutputFile(const char* path);
+    virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
+    virtual status_t setVideoSize(int width, int height);
+    virtual status_t setVideoFrameRate(int frames_per_second);
+    virtual status_t setParameters(const String8& params);
+    virtual status_t setListener(const sp<IMediaRecorderClient>& listener);
+    virtual status_t setClientName(const String16& clientName);
+    virtual status_t prepare();
+    virtual status_t getMaxAmplitude(int* max);
+    virtual status_t start();
+    virtual status_t stop();
+#ifdef BOARD_HAS_MEDIA_RECORDER_PAUSE
+    virtual status_t pause();
+#endif
+#ifdef BOARD_HAS_MEDIA_RECORDER_RESUME
+    virtual status_t resume();
+#endif
+    virtual status_t reset();
+    virtual status_t init();
+    virtual status_t close();
+    virtual status_t release();
+    virtual status_t dump(int fd, const Vector<String16>& args) const;
+    virtual sp<IGraphicBufferProducer> querySurfaceMediaSource();
+
+private:
+    sp<BpMediaRecorderObserver> media_recorder_observer;
+    MediaRecorderBase *recorder;
+    Mutex recorder_lock;
+};
+
+}
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder_factory.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "MediaRecorderFactory"
+
+#include "media_recorder_factory.h"
+#include "media_recorder_client.h"
+#include <hybris/media/media_recorder_layer.h>
+
+#include <gui/IGraphicBufferProducer.h>
+#include <media/IMediaRecorder.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__)
+
+namespace android {
+
+enum {
+    CREATE_MEDIA_RECORDER = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpMediaRecorderFactory: public BpInterface<IMediaRecorderFactory>
+{
+public:
+    BpMediaRecorderFactory(const sp<IBinder>& impl)
+        : BpInterface<IMediaRecorderFactory>(impl)
+    {
+    }
+
+    virtual sp<IMediaRecorder> createMediaRecorder()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorderFactory::getInterfaceDescriptor());
+        remote()->transact(CREATE_MEDIA_RECORDER, data, &reply);
+        return interface_cast<IMediaRecorder>(reply.readStrongBinder());
+    }
+};
+
+// ----------------------------------------------------------------------------
+
+IMPLEMENT_META_INTERFACE(MediaRecorderFactory, "android.media.IMediaRecorderFactory");
+
+// ----------------------------------------------------------------------
+
+status_t BnMediaRecorderFactory::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+        case CREATE_MEDIA_RECORDER: {
+            CHECK_INTERFACE(IMediaRecorderFactory, data, reply);
+            sp<IMediaRecorder> recorder = createMediaRecorder();
+            reply->writeStrongBinder(recorder->asBinder());
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+sp<MediaRecorderFactory> MediaRecorderFactory::media_recorder_factory;
+Mutex MediaRecorderFactory::s_lock;
+
+MediaRecorderFactory::MediaRecorderFactory()
+{
+    REPORT_FUNCTION();
+}
+
+MediaRecorderFactory::~MediaRecorderFactory()
+{
+    REPORT_FUNCTION();
+}
+
+/*!
+ * \brief Creates and adds the MediaRecorderFactory service to the default Binder ServiceManager
+ */
+void MediaRecorderFactory::instantiate()
+{
+    defaultServiceManager()->addService(
+            String16(IMediaRecorderFactory::exported_service_name()), factory_instance());
+    ALOGV("Added Binder service '%s' to ServiceManager", IMediaRecorderFactory::exported_service_name());
+}
+
+/*!
+ * \brief Creates a new MediaRecorderClient instance over Binder
+ * \return A new MediaRecorderClient instance
+ */
+sp<IMediaRecorder> MediaRecorderFactory::createMediaRecorder()
+{
+    REPORT_FUNCTION();
+    sp<MediaRecorderClient> recorder = new MediaRecorderClient();
+    return recorder;
+}
+
+/*!
+ * \brief Get a reference to the MediaRecorderFactory singleton instance
+ * \return The MediaRecorderFactory singleton instance
+ */
+sp<MediaRecorderFactory>& MediaRecorderFactory::factory_instance()
+{
+    REPORT_FUNCTION();
+    Mutex::Autolock _l(s_lock);
+    if (media_recorder_factory == NULL)
+    {
+        ALOGD("Creating new static instance of MediaRecorderFactory");
+        media_recorder_factory = new MediaRecorderFactory();
+    }
+
+    return media_recorder_factory;
+}
+
+} // namespace android
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder_factory.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef MEDIA_RECORDER_FACTORY_H_
+#define MEDIA_RECORDER_FACTORY_H_
+
+#include <media/IMediaRecorder.h>
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class Mutex;
+
+class IMediaRecorderFactory: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MediaRecorderFactory);
+
+    static const char* exported_service_name() { return "android.media.IMediaRecorderFactory"; }
+
+    virtual sp<IMediaRecorder> createMediaRecorder() = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMediaRecorderFactory: public BnInterface<IMediaRecorderFactory>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+class MediaRecorderFactory : public BnMediaRecorderFactory
+{
+public:
+    MediaRecorderFactory();
+    virtual ~MediaRecorderFactory();
+
+    static void instantiate();
+
+    virtual sp<IMediaRecorder> createMediaRecorder();
+private:
+    static sp<MediaRecorderFactory>& factory_instance();
+
+    static sp<MediaRecorderFactory> media_recorder_factory;
+    static Mutex s_lock;
+};
+
+}
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder_layer.cpp
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2013-2014 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ *              Guenter Schwann <guenter.schwann@canonical.com>
+ *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ */
+
+#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "MediaRecorderCompatibilityLayer"
+
+#include "media_recorder.h"
+
+#include <hybris/internal/camera_control.h>
+#include <hybris/media/media_recorder_layer.h>
+
+#include <utils/KeyedVector.h>
+#include <utils/Log.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__)
+
+using namespace android;
+
+/*!
+ * \brief The MediaRecorderListenerWrapper class is used to listen to camera events
+ * from the MediaRecorder instance
+ */
+class MediaRecorderListenerWrapper : public android::MediaRecorderListener
+{
+public:
+    MediaRecorderListenerWrapper()
+        : error_cb(NULL),
+          error_context(NULL),
+          read_audio_cb(NULL),
+          read_audio_context(NULL)
+{
+}
+
+    void notify(int msg, int ext1, int ext2)
+    {
+        ALOGV("\tmsg: %d, ext1: %d, ext2: %d \n", msg, ext1, ext2);
+
+        switch (msg) {
+            case android::MEDIA_RECORDER_EVENT_ERROR:
+                ALOGV("\tMEDIA_RECORDER_EVENT_ERROR msg\n");
+                // TODO: Extend this cb to include the error message
+                if (error_cb != NULL)
+                    error_cb(error_context);
+                else
+                    ALOGE("Failed to signal error to app layer, callback not set.");
+                break;
+            default:
+                ALOGV("\tUnknown notification\n");
+        }
+    }
+
+    void readAudio()
+    {
+        REPORT_FUNCTION();
+        if (read_audio_cb != NULL) {
+            read_audio_cb(read_audio_context);
+        }
+        else
+            ALOGW("Failed to call read_audio_cb since it's NULL");
+    }
+
+    void setErrorCb(on_recorder_msg_error cb, void *context)
+    {
+        REPORT_FUNCTION();
+        error_cb = cb;
+        error_context = context;
+    }
+
+    void setReadAudioCb(on_recorder_read_audio cb, void *context)
+    {
+        REPORT_FUNCTION();
+        read_audio_cb = cb;
+        read_audio_context = context;
+    }
+
+private:
+    on_recorder_msg_error error_cb;
+    void *error_context;
+    on_recorder_read_audio read_audio_cb;
+    void *read_audio_context;
+};
+
+/*!
+ * \brief The MediaRecorderWrapper struct wraps the MediaRecorder class
+ */
+struct MediaRecorderWrapper : public android::MediaRecorder
+{
+public:
+    MediaRecorderWrapper()
+        : MediaRecorder(),
+          media_recorder_listener(new MediaRecorderListenerWrapper())
+{
+}
+
+    ~MediaRecorderWrapper()
+    {
+        reset();
+    }
+
+    void init()
+    {
+        setListener(media_recorder_listener);
+    }
+
+    void setErrorCb(on_recorder_msg_error cb, void *context)
+    {
+        REPORT_FUNCTION();
+
+        assert(media_recorder_listener != NULL);
+        media_recorder_listener->setErrorCb(cb, context);
+    }
+
+    void setAudioReadCb(on_recorder_read_audio cb, void *context)
+    {
+        REPORT_FUNCTION();
+
+        assert(media_recorder_listener != NULL);
+        media_recorder_listener->setReadAudioCb(cb, context);
+    }
+
+private:
+    android::sp<MediaRecorderListenerWrapper> media_recorder_listener;
+};
+
+/*!
+ * \brief android_recorder_set_error_cb
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param cb The callback function to be called when a recording error occurs
+ * \param user context to pass through to the error handler
+ */
+void android_recorder_set_error_cb(MediaRecorderWrapper *mr, on_recorder_msg_error cb,
+        void *context)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return;
+    }
+
+    mr->setErrorCb(cb, context);
+}
+
+void android_recorder_set_audio_read_cb(MediaRecorderWrapper *mr, on_recorder_read_audio cb,
+        void *context)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return;
+    }
+
+    mr->setAudioReadCb(cb, context);
+}
+
+/*!
+ * \brief android_media_new_recorder creates a new MediaRecorder
+ * \return New MediaRecorder object, or NULL if the object could not be created.
+ */
+MediaRecorderWrapper *android_media_new_recorder()
+{
+    REPORT_FUNCTION();
+
+    MediaRecorderWrapper *mr = new MediaRecorderWrapper;
+    if (mr == NULL) {
+        ALOGE("Failed to create new MediaRecorder instance.");
+        return NULL;
+    }
+
+    return mr;
+}
+
+/*!
+ * \brief android_recorder_initCheck
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \return negative value if an error occured
+ */
+int android_recorder_initCheck(MediaRecorderWrapper *mr)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->initCheck();
+}
+
+/*!
+ * \brief android_recorder_setCamera sets the camera object for recording videos from the camera
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param control Wrapper for the camera (see camera in hybris)
+ * \return negative value if an error occured
+ */
+int android_recorder_setCamera(MediaRecorderWrapper *mr, CameraControl* control)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+    if (control == NULL) {
+        ALOGE("control must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    mr->init();
+
+    return mr->setCamera(control->camera->remote(), control->camera->getRecordingProxy());
+}
+
+/*!
+ * \brief android_recorder_setVideoSource sets the video source.
+ * If no video source is set, only audio is recorded.
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param vs The video source. It's either a camera or a gralloc buffer
+ * \return negative value if an error occured
+ */
+int android_recorder_setVideoSource(MediaRecorderWrapper *mr, VideoSource vs)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setVideoSource(static_cast<int>(vs));
+}
+
+/*!
+ * \brief android_recorder_setAudioSource
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param as The audio source.
+ * \return negative value if an error occured
+ */
+int android_recorder_setAudioSource(MediaRecorderWrapper *mr, AudioSource as)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setAudioSource(static_cast<int>(as));
+}
+
+/*!
+ * \brief android_recorder_setOutputFormat
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param of The output file container format
+ * \return negative value if an error occured
+ */
+int android_recorder_setOutputFormat(MediaRecorderWrapper *mr, OutputFormat of)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setOutputFormat(static_cast<int>(of));
+}
+
+/*!
+ * \brief android_recorder_setVideoEncoder
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param ve The video encoder sets the codec type for encoding/recording video
+ * \return negative value if an error occured
+ */
+int android_recorder_setVideoEncoder(MediaRecorderWrapper *mr, VideoEncoder ve)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setVideoEncoder(static_cast<int>(ve));
+}
+
+/*!
+ * \brief android_recorder_setAudioEncoder
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param ae The audio encoder sets the codec type for encoding/recording audio
+ * \return negative value if an error occured
+ */
+int android_recorder_setAudioEncoder(MediaRecorderWrapper *mr, AudioEncoder ae)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setAudioEncoder(static_cast<int>(ae));
+}
+
+/*!
+ * \brief android_recorder_setOutputFile sets the output file to the given file descriptor
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param fd File descriptor of an open file, that the stream can be written to
+ * \return negative value if an error occured
+ */
+int android_recorder_setOutputFile(MediaRecorderWrapper *mr, int fd)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setOutputFile(fd, 0, 0);
+}
+
+/*!
+ * \brief android_recorder_setVideoSize
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param width output width for the video to record
+ * \param height output height for the video to record
+ * \return negative value if an error occured
+ */
+int android_recorder_setVideoSize(MediaRecorderWrapper *mr, int width, int height)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setVideoSize(width, height);
+}
+
+/*!
+ * \brief android_recorder_setVideoFrameRate
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param frames_per_second How many frames per second to record at (e.g. 720p is typically 30)
+ * \return negative value if an error occured
+ */
+int android_recorder_setVideoFrameRate(MediaRecorderWrapper *mr, int frames_per_second)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->setVideoFrameRate(frames_per_second);
+}
+
+/*!
+ * \brief android_recorder_setParameters sets a parameter. Even those without
+ * explicit function.
+ * For possible parameter pairs look for examples in StagefrightRecorder::setParameter()
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \param parameters list of parameters. format is "parameter1=value;parameter2=value"
+ * \return negative value if an error occured
+ */
+int android_recorder_setParameters(MediaRecorderWrapper *mr, const char *parameters)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    android::String8 params(parameters);
+    return mr->setParameters(params);
+}
+
+/*!
+ * \brief android_recorder_start starts the recording.
+ * The MediaRecorder has to be in state "prepared" (call android_recorder_prepare() first)
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \return negative value if an error occured
+ */
+int android_recorder_start(MediaRecorderWrapper *mr)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->start();
+}
+
+/*!
+ * \brief android_recorder_stop Stops a running recording.
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \return negative value if an error occured
+ */
+int android_recorder_stop(MediaRecorderWrapper *mr)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->stop();
+}
+
+/*!
+ * \brief android_recorder_prepare put the MediaRecorder into state "prepare"
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \return negative value if an error occured
+ */
+int android_recorder_prepare(MediaRecorderWrapper *mr)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->prepare();
+}
+
+/*!
+ * \brief android_recorder_reset resets the MediaRecorder
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \return negative value if an error occured
+ */
+int android_recorder_reset(MediaRecorderWrapper *mr)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->reset();
+}
+
+/*!
+ * \brief android_recorder_close closes the MediaRecorder
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \return negative value if an error occured
+ */
+int android_recorder_close(MediaRecorderWrapper *mr)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->close();
+}
+
+/*!
+ * \brief android_recorder_release releases the MediaRecorder resources
+ * This deletes the MediaRecorder instance. So don't use the instance after calling this function.
+ * \param mr A MediaRecorder instance, created by calling android_media_new_recorder()
+ * \return negative value if an error occured
+ */
+int android_recorder_release(MediaRecorderWrapper *mr)
+{
+    REPORT_FUNCTION();
+
+    if (mr == NULL) {
+        ALOGE("mr must not be NULL");
+        return android::BAD_VALUE;
+    }
+
+    return mr->release();
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder_observer.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Ricardo Mendoza <ricardo.mendoza@canonical.com>
+ */
+
+// Uncomment to enabe verbose debug output
+//#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "MediaRecorderObserver"
+
+#include "media_recorder_observer.h"
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <binder/ProcessState.h>
+
+#include <binder/IServiceManager.h>
+
+#include <utils/Vector.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+IMPLEMENT_META_INTERFACE(MediaRecorderObserver, "android.media.IMediaRecorderObserver");
+
+status_t BnMediaRecorderObserver::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+        case RECORDING_STARTED: {
+            CHECK_INTERFACE(IMediaRecorderObserver, data, reply);
+            recordingStarted();
+
+            return NO_ERROR;
+        } break;
+        case RECORDING_STOPPED: {
+            CHECK_INTERFACE(IMediaRecorderObserver, data, reply);
+            recordingStopped();
+
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+MediaRecorderObserver::MediaRecorderObserver()
+{
+    defaultServiceManager()->addService(
+        String16(IMediaRecorderObserver::exported_service_name()), this);
+
+    ProcessState::self()->startThreadPool();
+}
+
+void MediaRecorderObserver::recordingStarted()
+{
+    if (media_recording_started != nullptr)
+        media_recording_started(true, cb_context);
+}
+
+void MediaRecorderObserver::recordingStopped()
+{
+    if (media_recording_started != nullptr)
+        media_recording_started(false, cb_context);
+}
+
+void MediaRecorderObserver::setRecordingSignalCb(media_recording_started_cb cb, void *context)
+{
+    if (cb != NULL) {
+        cb_context = context;
+        media_recording_started = cb;
+    }
+}
+
+};
+
+// C API
+
+struct MediaRecorderObserver {
+    MediaRecorderObserver(android::MediaRecorderObserver *observer)
+        : impl(observer)
+    {
+    }
+
+    android::MediaRecorderObserver* impl;
+};
+
+MediaRecorderObserver* android_media_recorder_observer_new()
+{
+    MediaRecorderObserver *p = new MediaRecorderObserver(new android::MediaRecorderObserver);
+
+    if (p == NULL) {
+        ALOGE("Failed to create new MediaRecorderObserver instance.");
+        return NULL;
+    }
+
+    return p;
+}
+
+void android_media_recorder_observer_set_cb(MediaRecorderObserver *observer, media_recording_started_cb cb, void *context)
+{
+    if (observer == NULL)
+        return;
+
+    auto p = observer->impl;
+
+    p->setRecordingSignalCb(cb, context);
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/media_recorder_observer.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Ricardo Mendoza <ricardo.mendoza@canonical.com>
+ */
+
+#ifndef MEDIA_RECORDER_OBSERVER_H_
+#define MEDIA_RECORDER_OBSERVER_H_
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+#include <hybris/media/media_recorder_layer.h>
+
+namespace android {
+
+enum {
+    RECORDING_STARTED = IBinder::FIRST_CALL_TRANSACTION,
+    RECORDING_STOPPED,
+};
+
+class IMediaRecorderObserver: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MediaRecorderObserver);
+
+    static const char* exported_service_name() { return "android.media.IMediaRecorderObserver"; }
+
+    virtual void recordingStarted(void) = 0;
+    virtual void recordingStopped(void) = 0;
+};
+
+class BnMediaRecorderObserver: public BnInterface<IMediaRecorderObserver>
+{
+public:
+    virtual status_t onTransact( uint32_t code,
+                                 const Parcel& data,
+                                 Parcel* reply,
+                                 uint32_t flags = 0);
+};
+
+class BpMediaRecorderObserver: public BpInterface<IMediaRecorderObserver>
+{
+public:
+    BpMediaRecorderObserver(const sp<IBinder>& impl)
+        : BpInterface<IMediaRecorderObserver>(impl)
+    {
+    }
+
+    virtual void recordingStarted()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorderObserver::getInterfaceDescriptor());
+        remote()->transact(RECORDING_STARTED, data, &reply);
+        return;
+    }
+
+    virtual void recordingStopped()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorderObserver::getInterfaceDescriptor());
+        remote()->transact(RECORDING_STOPPED, data, &reply);
+        return;
+    }
+};
+
+class MediaRecorderObserver : public BnMediaRecorderObserver
+{
+public:
+    MediaRecorderObserver();
+    ~MediaRecorderObserver() = default;
+
+    virtual void recordingStarted(void);
+    virtual void recordingStopped(void);
+
+    virtual void setRecordingSignalCb(media_recording_started_cb cb, void *context);
+
+private:
+    media_recording_started_cb media_recording_started;
+    void *cb_context;
+};
+
+}; // namespace android
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/surface_texture_client_hybris.cpp
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+// Uncomment to enable verbose debug output
+#define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "SurfaceTextureClientHybris"
+
+#include <hybris/media/surface_texture_client_hybris.h>
+#include "surface_texture_client_hybris_priv.h"
+#include "decoding_service_priv.h"
+
+#include <ui/GraphicBuffer.h>
+#include <utils/Log.h>
+#include <ui/Region.h>
+#include <gui/Surface.h>
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+#include <gui/SurfaceTextureClient.h>
+#endif
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/GLConsumer.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__);
+
+using namespace android;
+
+// ----- Begin _SurfaceTextureClientHybris API ----- //
+
+static inline _SurfaceTextureClientHybris *get_internal_stch(SurfaceTextureClientHybris stc, const char * func)
+{
+    if (stc == NULL)
+    {
+        ALOGE("stc must not be NULL (%s)", func);
+        return NULL;
+    }
+
+    _SurfaceTextureClientHybris *s = static_cast<_SurfaceTextureClientHybris*>(stc);
+    assert(s->refcount >= 1);
+
+    return s;
+}
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris()
+    : refcount(1),
+      ready(false)
+{
+    REPORT_FUNCTION()
+}
+#endif
+
+#if ANDROID_VERSION_MAJOR==5
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp<IGraphicBufferProducer> &st)
+    : Surface::Surface(st, true),
+      refcount(1),
+      ready(false)
+{
+    REPORT_FUNCTION()
+}
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR>=4
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp<BufferQueue> &bq)
+    : Surface::Surface(bq, true),
+      refcount(1),
+      ready(false)
+{
+    REPORT_FUNCTION()
+}
+
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp<IGraphicBufferProducer> &st)
+    : Surface::Surface(st, true),
+      refcount(1),
+      ready(false)
+{
+    REPORT_FUNCTION()
+}
+#endif
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const _SurfaceTextureClientHybris &stch)
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    : SurfaceTextureClient::SurfaceTextureClient(),
+#else
+    : Surface::Surface(new BufferQueue(), true),
+#endif
+      refcount(stch.refcount),
+      ready(false)
+{
+    REPORT_FUNCTION()
+}
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp<ISurfaceTexture> &st)
+    : SurfaceTextureClient::SurfaceTextureClient(st),
+#else
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp<IGraphicBufferProducer> &st)
+    : Surface::Surface(st, false),
+#endif
+      refcount(1),
+      ready(false)
+{
+    REPORT_FUNCTION()
+}
+#endif
+
+_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const android::sp<android::IGraphicBufferProducer> &st,
+        bool producerIsControlledByApp)
+    : Surface::Surface(st, producerIsControlledByApp),
+      refcount(1),
+      ready(false)
+{
+    REPORT_FUNCTION()
+}
+
+_SurfaceTextureClientHybris::~_SurfaceTextureClientHybris()
+{
+    REPORT_FUNCTION()
+
+    ready = false;
+}
+
+bool _SurfaceTextureClientHybris::isReady() const
+{
+    return ready;
+}
+
+void _SurfaceTextureClientHybris::setReady(bool ready)
+{
+    this->ready = ready;
+}
+
+int _SurfaceTextureClientHybris::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd)
+{
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    return SurfaceTextureClient::dequeueBuffer(buffer, fenceFd);
+#else
+    return Surface::dequeueBuffer(buffer, fenceFd);
+#endif
+}
+
+int _SurfaceTextureClientHybris::queueBuffer(ANativeWindowBuffer* buffer, int fenceFd)
+{
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    return SurfaceTextureClient::queueBuffer(buffer, fenceFd);
+#else
+    return Surface::queueBuffer(buffer, fenceFd);
+#endif
+}
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+void _SurfaceTextureClientHybris::setISurfaceTexture(const sp<ISurfaceTexture>& surface_texture)
+{
+    SurfaceTextureClient::setISurfaceTexture(surface_texture);
+#else
+void _SurfaceTextureClientHybris::setISurfaceTexture(const sp<IGraphicBufferProducer>& surface_texture)
+{
+    // We don't need to set up the IGraphicBufferProducer as stc needs it when created
+#endif
+
+    // Ready for rendering
+    ready = true;
+}
+
+void _SurfaceTextureClientHybris::setHardwareRendering(bool do_hardware_rendering)
+{
+    hardware_rendering = do_hardware_rendering;
+}
+
+bool _SurfaceTextureClientHybris::hardwareRendering()
+{
+  return hardware_rendering;
+}
+
+// ----- End _SurfaceTextureClientHybris API ----- //
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+static inline void set_surface(_SurfaceTextureClientHybris *stch, const sp<SurfaceTexture> &surface_texture)
+#else
+static inline void set_surface(_SurfaceTextureClientHybris *stch, const sp<GLConsumer> &surface_texture)
+#endif
+{
+    REPORT_FUNCTION()
+
+    if (stch == NULL)
+        return;
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    stch->setISurfaceTexture(surface_texture->getBufferQueue());
+#else
+    stch->setISurfaceTexture(stch->getIGraphicBufferProducer());
+#endif
+}
+
+SurfaceTextureClientHybris surface_texture_client_create_by_id(unsigned int texture_id)
+{
+    REPORT_FUNCTION()
+
+    if (texture_id == 0)
+    {
+        ALOGE("Cannot create new SurfaceTextureClientHybris, texture id must be > 0.");
+        return NULL;
+    }
+#if ANDROID_VERSION_MAJOR==5
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+
+    _SurfaceTextureClientHybris *stch(new _SurfaceTextureClientHybris(producer));
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
+    // Use a new native buffer allocator vs the default one, which means it'll use the proper one
+    // that will allow rendering to work with Mir
+    sp<NativeBufferAlloc> native_alloc(new NativeBufferAlloc());
+
+    sp<BufferQueue> buffer_queue(new BufferQueue(false, NULL, native_alloc));
+    _SurfaceTextureClientHybris *stch(new _SurfaceTextureClientHybris);
+#else
+    sp<BufferQueue> buffer_queue(new BufferQueue(NULL));
+    _SurfaceTextureClientHybris *stch(new _SurfaceTextureClientHybris(buffer_queue));
+#endif
+
+    ALOGD("stch: %p (%s)", stch, __PRETTY_FUNCTION__);
+
+    if (stch->surface_texture != NULL)
+      stch->surface_texture.clear();
+
+    const bool allow_synchronous_mode = true;
+#if ANDROID_VERSION_MAJOR==5
+    stch->surface_texture = new GLConsumer(consumer, texture_id, GL_TEXTURE_EXTERNAL_OES, true, true);
+#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    stch->surface_texture = new SurfaceTexture(texture_id, allow_synchronous_mode, GL_TEXTURE_EXTERNAL_OES, true, buffer_queue);
+    set_surface(stch, stch->surface_texture);
+#else
+    stch->surface_texture = new GLConsumer(buffer_queue, texture_id, GL_TEXTURE_EXTERNAL_OES, true, true);
+#endif
+    set_surface(stch, stch->surface_texture);
+
+    return stch;
+}
+
+SurfaceTextureClientHybris surface_texture_client_create_by_igbp(IGBPWrapperHybris wrapper)
+{
+    if (wrapper == NULL)
+    {
+        ALOGE("Cannot create new SurfaceTextureClientHybris, wrapper must not be NULL.");
+        return NULL;
+    }
+
+    IGBPWrapper *igbp = static_cast<IGBPWrapper*>(wrapper);
+    // The producer should be the same BufferQueue as what the client is using but over Binder
+    // Allow the app to control the producer side BufferQueue
+    _SurfaceTextureClientHybris *stch(new _SurfaceTextureClientHybris(igbp->producer, true));
+    // Ready for rendering
+    stch->setReady();
+    return stch;
+}
+
+GLConsumerWrapperHybris gl_consumer_create_by_id_with_igbc(unsigned int texture_id, IGBCWrapperHybris wrapper)
+{
+    REPORT_FUNCTION()
+
+    if (texture_id == 0)
+    {
+        ALOGE("Cannot create new SurfaceTextureClientHybris, texture id must be > 0.");
+        return NULL;
+    }
+
+    if (wrapper == NULL)
+    {
+        ALOGE("Cannot create new GLConsumerHybris, wrapper must not be NULL.");
+        return NULL;
+    }
+
+    IGBCWrapper *igbc = static_cast<IGBCWrapper*>(wrapper);
+    // Use a fence guard and consumer is controlled by app:
+    sp<_GLConsumerHybris> gl_consumer = new _GLConsumerHybris(igbc->consumer, texture_id, GL_TEXTURE_EXTERNAL_OES, true, true);
+    GLConsumerWrapper *glc_wrapper = new GLConsumerWrapper(gl_consumer);
+
+    return glc_wrapper;
+}
+
+int gl_consumer_set_frame_available_cb(GLConsumerWrapperHybris wrapper, FrameAvailableCbHybris cb, void *context)
+{
+    REPORT_FUNCTION()
+
+    if (wrapper == NULL)
+    {
+        ALOGE("Cannot set GLConsumerWrapperHybris, wrapper must not be NULL");
+        return BAD_VALUE;
+    }
+    if (cb == NULL)
+    {
+        ALOGE("Cannot set FrameAvailableCbHybris, cb must not be NULL");
+        return BAD_VALUE;
+    }
+
+    GLConsumerWrapper *glc_wrapper = static_cast<GLConsumerWrapper*>(wrapper);
+    sp<_GLConsumerHybris> glc_hybris = static_cast<_GLConsumerHybris*>(glc_wrapper->consumer.get());
+    glc_hybris->createFrameAvailableListener(cb, wrapper, context);
+
+    return OK;
+}
+
+void gl_consumer_get_transformation_matrix(GLConsumerWrapperHybris wrapper, float *matrix)
+{
+    REPORT_FUNCTION()
+
+    if (wrapper == NULL)
+    {
+        ALOGE("Cannot set GLConsumerWrapperHybris, wrapper must not be NULL");
+        return;
+    }
+
+    GLConsumerWrapper *glc_wrapper = static_cast<GLConsumerWrapper*>(wrapper);
+    sp<_GLConsumerHybris> glc_hybris = static_cast<_GLConsumerHybris*>(glc_wrapper->consumer.get());
+    glc_hybris->getTransformMatrix(static_cast<GLfloat*>(matrix));
+}
+
+void gl_consumer_update_texture(GLConsumerWrapperHybris wrapper)
+{
+    REPORT_FUNCTION()
+
+    if (wrapper == NULL)
+    {
+        ALOGE("Cannot set GLConsumerWrapperHybris, wrapper must not be NULL");
+        return;
+    }
+
+    GLConsumerWrapper *glc_wrapper = static_cast<GLConsumerWrapper*>(wrapper);
+    sp<_GLConsumerHybris> glc_hybris = static_cast<_GLConsumerHybris*>(glc_wrapper->consumer.get());
+    glc_hybris->updateTexImage();
+}
+
+uint8_t surface_texture_client_is_ready_for_rendering(SurfaceTextureClientHybris stc)
+{
+    REPORT_FUNCTION()
+
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+        return false;
+
+    return static_cast<uint8_t>(s->isReady());
+}
+
+uint8_t surface_texture_client_hardware_rendering(SurfaceTextureClientHybris stc)
+{
+    REPORT_FUNCTION()
+
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+        return false;
+
+    return s->hardwareRendering();
+}
+
+void surface_texture_client_set_hardware_rendering(SurfaceTextureClientHybris stc, uint8_t hardware_rendering)
+{
+    REPORT_FUNCTION()
+
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+        return;
+
+    s->setHardwareRendering(static_cast<bool>(hardware_rendering));
+}
+
+void surface_texture_client_get_transformation_matrix(SurfaceTextureClientHybris stc, float *matrix)
+{
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+        return;
+
+    s->surface_texture->getTransformMatrix(static_cast<GLfloat*>(matrix));
+}
+
+void surface_texture_client_update_texture(SurfaceTextureClientHybris stc)
+{
+    REPORT_FUNCTION()
+
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+        return;
+
+    s->surface_texture->updateTexImage();
+}
+
+void surface_texture_client_destroy(SurfaceTextureClientHybris stc)
+{
+    REPORT_FUNCTION()
+
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+    {
+        ALOGE("s == NULL, cannot destroy SurfaceTextureClientHybris instance");
+        return;
+    }
+
+    s->refcount = 0;
+
+    delete s;
+}
+
+void surface_texture_client_ref(SurfaceTextureClientHybris stc)
+{
+    REPORT_FUNCTION()
+
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+        return;
+
+    s->refcount++;
+}
+
+void surface_texture_client_unref(SurfaceTextureClientHybris stc)
+{
+    REPORT_FUNCTION()
+
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+    {
+        ALOGE("s == NULL, cannot unref SurfaceTextureClientHybris instance");
+        return;
+    }
+
+    if (s->refcount > 1)
+        s->refcount--;
+    else
+        surface_texture_client_destroy (stc);
+}
+
+void surface_texture_client_set_surface_texture(SurfaceTextureClientHybris stc, EGLNativeWindowType native_window)
+{
+    _SurfaceTextureClientHybris *s = get_internal_stch(stc, __PRETTY_FUNCTION__);
+    if (s == NULL)
+        return;
+
+    if (native_window == NULL)
+    {
+        ALOGE("native_window must not be NULL");
+        return;
+    }
+
+    sp<Surface> surface = static_cast<Surface*>(native_window);
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    s->setISurfaceTexture(surface->getSurfaceTexture());
+#else
+    s->setISurfaceTexture(surface->getIGraphicBufferProducer());
+#endif
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/compat/media/surface_texture_client_hybris_priv.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef SURFACE_TEXTURE_CLIENT_HYBRIS_PRIV_H
+#define SURFACE_TEXTURE_CLIENT_HYBRIS_PRIV_H
+
+#include "hybris/media/surface_texture_client_hybris.h"
+
+#include <gui/Surface.h>
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+#include <gui/SurfaceTextureClient.h>
+#else
+#include <gui/GLConsumer.h>
+#endif
+
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+struct _SurfaceTextureClientHybris : public android::SurfaceTextureClient
+#else
+struct _SurfaceTextureClientHybris : public android::Surface
+#endif
+{
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    _SurfaceTextureClientHybris();
+#endif
+    _SurfaceTextureClientHybris(const _SurfaceTextureClientHybris &stch);
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    _SurfaceTextureClientHybris(const android::sp<android::ISurfaceTexture> &st);
+#else
+    _SurfaceTextureClientHybris(const android::sp<android::IGraphicBufferProducer> &st);
+    _SurfaceTextureClientHybris(const android::sp<android::IGraphicBufferProducer> &st,
+            bool producerIsControlledByApp);
+    _SurfaceTextureClientHybris(const android::sp<android::BufferQueue> &bq);
+#endif
+    ~_SurfaceTextureClientHybris();
+
+    /** Has a texture id or EGLNativeWindowType been passed in, meaning rendering will function? **/
+    bool isReady() const;
+    void setReady(bool ready = true);
+
+public:
+    int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
+    int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    void setISurfaceTexture(const android::sp<android::ISurfaceTexture>& surface_texture);
+#else
+    void setISurfaceTexture(const android::sp<android::IGraphicBufferProducer>& surface_texture);
+#endif
+    void setHardwareRendering(bool do_hardware_rendering);
+    bool hardwareRendering();
+
+    unsigned int refcount;
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
+    android::sp<android::SurfaceTexture> surface_texture;
+#else
+    android::sp<android::GLConsumer> surface_texture;
+#endif
+
+private:
+    bool ready;
+    bool hardware_rendering;
+};
+
+namespace android {
+
+class _GLConsumerHybris : public GLConsumer
+{
+    class FrameAvailableListener : public GLConsumer::FrameAvailableListener
+    {
+    public:
+        FrameAvailableListener()
+            : frame_available_cb(NULL),
+              glc_wrapper(NULL),
+              context(NULL)
+        {
+        }
+
+#if ANDROID_VERSION_MAJOR==5 && ANDROID_VERSION_MINOR>=1
+		virtual void onFrameAvailable(const android::BufferItem& item)
+#else
+        virtual void onFrameAvailable()
+#endif
+        {
+            if (frame_available_cb != NULL)
+                frame_available_cb(glc_wrapper, context);
+            else
+                ALOGE("Failed to call, frame_available_cb is NULL");
+        }
+
+        void setFrameAvailableCbHybris(FrameAvailableCbHybris cb, GLConsumerWrapperHybris wrapper, void *context)
+        {
+            frame_available_cb = cb;
+            glc_wrapper = wrapper;
+            this->context = context;
+        }
+
+    private:
+        FrameAvailableCbHybris frame_available_cb;
+        GLConsumerWrapperHybris glc_wrapper;
+        void *context;
+    };
+
+public:
+    _GLConsumerHybris(const sp<IGraphicBufferConsumer>& bq,
+            uint32_t tex, uint32_t textureTarget = TEXTURE_EXTERNAL,
+            bool useFenceSync = true, bool isControlledByApp = false)
+        : GLConsumer(bq, tex, textureTarget, useFenceSync, isControlledByApp)
+    {
+    }
+
+    void createFrameAvailableListener(FrameAvailableCbHybris cb, GLConsumerWrapperHybris wrapper, void *context)
+    {
+        frame_available_listener = new _GLConsumerHybris::FrameAvailableListener();
+        frame_available_listener->setFrameAvailableCbHybris(cb, wrapper, context);
+        setFrameAvailableListener(frame_available_listener);
+    }
+
+private:
+    sp<_GLConsumerHybris::FrameAvailableListener> frame_available_listener;
+};
+
+}; // namespace android
+
+#endif
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/surface_flinger/Android.mk
+++ libhybris-0.1.0+git20151016+6d424c9/compat/surface_flinger/Android.mk
@@ -1,5 +1,6 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
+include $(LOCAL_PATH)/../Android.common.mk
 
 HYBRIS_PATH := $(LOCAL_PATH)/../../hybris
 
@@ -8,6 +9,7 @@ LOCAL_SRC_FILES:= \
 
 LOCAL_MODULE:= libsf_compat_layer
 LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
 
 LOCAL_C_INCLUDES := \
 	$(HYBRIS_PATH)/include
@@ -30,6 +32,7 @@ LOCAL_SRC_FILES:= \
 
 LOCAL_MODULE:= direct_sf_test
 LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
 
 LOCAL_C_INCLUDES := \
 	$(HYBRIS_PATH)/include
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/surface_flinger/surface_flinger_compatibility_layer.cpp
+++ libhybris-0.1.0+git20151016+6d424c9/compat/surface_flinger/surface_flinger_compatibility_layer.cpp
@@ -28,6 +28,9 @@
 #include <ui/PixelFormat.h>
 #include <ui/Region.h>
 #include <ui/Rect.h>
+#if ANDROID_VERSION_MAJOR==5
+  #include <hardware/hwcomposer_defs.h>
+#endif
 
 #include <cassert>
 #include <cstdio>
@@ -80,7 +83,11 @@ void sf_blank(size_t display_id)
 		return;
 	}
 
+#if ANDROID_VERSION_MAJOR<=4
 	android::SurfaceComposerClient::blankDisplay(display);
+#elif ANDROID_VERSION_MAJOR==5
+	android::SurfaceComposerClient::setDisplayPowerMode(display, HWC_POWER_MODE_OFF);
+#endif
 }
 
 void sf_unblank(size_t display_id)
@@ -98,7 +105,11 @@ void sf_unblank(size_t display_id)
 		return;
 	}
 
+#if ANDROID_VERSION_MAJOR<=4
 	android::SurfaceComposerClient::unblankDisplay(display);
+#elif ANDROID_VERSION_MAJOR==5
+	android::SurfaceComposerClient::setDisplayPowerMode(display, HWC_POWER_MODE_NORMAL);
+#endif
 }
 
 size_t sf_get_display_width(size_t display_id)
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/ui/Android.mk
+++ libhybris-0.1.0+git20151016+6d424c9/compat/ui/Android.mk
@@ -1,5 +1,6 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
+include $(LOCAL_PATH)/../Android.common.mk
 
 HYBRIS_PATH := $(LOCAL_PATH)/../../hybris
 
@@ -8,6 +9,7 @@ LOCAL_SRC_FILES:= \
 
 LOCAL_MODULE:= libui_compat_layer
 LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
 
 LOCAL_C_INCLUDES := \
 	$(HYBRIS_PATH)/include \
--- libhybris-0.1.0+git20151016+6d424c9.orig/compat/ui/ui_compatibility_layer.cpp
+++ libhybris-0.1.0+git20151016+6d424c9/compat/ui/ui_compatibility_layer.cpp
@@ -126,6 +126,7 @@ void* graphic_buffer_get_native_buffer(s
     return buffer->self->getNativeBuffer();
 }
 
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
 void graphic_buffer_set_index(struct graphic_buffer *buffer, int index)
 {
     return buffer->self->setIndex(index);
@@ -135,6 +136,7 @@ int graphic_buffer_get_index(struct grap
 {
     return buffer->self->getIndex();
 }
+#endif
 
 int graphic_buffer_init_check(struct graphic_buffer *buffer)
 {
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/Makefile.am
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/Makefile.am
@@ -6,7 +6,7 @@ endif
 if HAS_ANDROID_5_0_0
 SUBDIRS += libsync
 endif
-SUBDIRS += egl glesv1 glesv2 ui sf input camera vibrator
+SUBDIRS += egl glesv1 glesv2 ui sf input camera vibrator media wifi
 
 if HAS_LIBNFC_NXP_HEADERS
 SUBDIRS += libnfc_nxp libnfc_ndef_nxp
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/camera/camera.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/camera/camera.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Canonical Ltd
+ * Copyright (C) 2013 - 2014 Canonical Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -31,8 +31,11 @@
 HYBRIS_LIBRARY_INITIALIZE(camera, COMPAT_LIBRARY_PATH);
 
 HYBRIS_IMPLEMENT_FUNCTION0(camera, int, android_camera_get_number_of_devices);
+HYBRIS_IMPLEMENT_FUNCTION3(camera, int, android_camera_get_device_info, int32_t, int*, int*);
 HYBRIS_IMPLEMENT_FUNCTION2(camera, struct CameraControl*, android_camera_connect_to,
 	CameraType, struct CameraControlListener*);
+HYBRIS_IMPLEMENT_FUNCTION2(camera, struct CameraControl*, android_camera_connect_by_id,
+	int32_t, struct CameraControlListener*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_disconnect,
 	struct CameraControl*);
 HYBRIS_IMPLEMENT_FUNCTION1(camera, int, android_camera_lock, struct CameraControl*);
@@ -52,8 +55,12 @@ HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera,
 	struct CameraControl*, SceneMode);
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_auto_focus_mode,
 	struct CameraControl*, AutoFocusMode);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_preview_format,
+	struct CameraControl*, CameraPixelFormat);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_set_picture_size,
 	struct CameraControl*, int, int);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_set_thumbnail_size,
+	struct CameraControl*, int, int);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_set_preview_size,
 	struct CameraControl*, int, int);
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_display_orientation,
@@ -66,12 +73,20 @@ HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera,
 	struct CameraControl*, FocusRegion*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_reset_focus_region,
 	struct CameraControl*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_metering_region,
+        struct CameraControl*, MeteringRegion*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_reset_metering_region,
+        struct CameraControl*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_preview_fps,
 	struct CameraControl*, int);
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_rotation,
 	struct CameraControl*, int);
+HYBRIS_IMPLEMENT_VOID_FUNCTION6(camera, android_camera_set_location,
+	struct CameraControl*, const float*, const float*, const float*, int, const char*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_set_video_size,
 	struct CameraControl*, int, int);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_jpeg_quality,
+	struct CameraControl*, int);
 
 // Getters
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_get_effect_mode,
@@ -88,6 +103,8 @@ HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera,
 	struct CameraControl*, int*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_get_picture_size,
 	struct CameraControl*, int*, int*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_get_thumbnail_size,
+	struct CameraControl*, int*, int*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_get_preview_size,
 	struct CameraControl*, int*, int*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_get_preview_fps_range,
@@ -98,14 +115,22 @@ HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera,
 	struct CameraControl*, float*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_get_video_size,
 	struct CameraControl*, int*, int*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_get_jpeg_quality,
+	struct CameraControl*, int*);
 
 // Enumerators
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_enumerate_supported_picture_sizes,
 	struct CameraControl*, size_callback, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_enumerate_supported_thumbnail_sizes,
+	struct CameraControl*, size_callback, void*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_enumerate_supported_preview_sizes,
 	struct CameraControl*, size_callback, void*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_enumerate_supported_video_sizes,
 	struct CameraControl*, size_callback, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_enumerate_supported_scene_modes,
+	struct CameraControl*, scene_mode_callback, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(camera, android_camera_enumerate_supported_flash_modes,
+	struct CameraControl*, flash_mode_callback, void*);
 
 HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_update_preview_texture, struct CameraControl*);
 
@@ -118,3 +143,6 @@ HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera,
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_zoom, struct CameraControl*, int32_t);
 HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_stop_zoom, struct CameraControl*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_take_snapshot, struct CameraControl*);
+
+HYBRIS_IMPLEMENT_FUNCTION2(camera, int, android_camera_set_preview_callback_mode,
+	struct CameraControl*, PreviewCallbackMode);
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/Makefile.am
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/Makefile.am
@@ -36,6 +36,9 @@ endif
 if WANT_DEBUG
 libhybris_common_la_CFLAGS += -ggdb -O0
 endif
+if WANT_MALI_QUIRKS
+libhybris_common_la_CFLAGS += -DMALI_QUIRKS
+endif
 libhybris_common_la_LDFLAGS = \
 	-ldl \
 	-lrt \
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/hooks.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/hooks.c
@@ -27,6 +27,7 @@
 #include <stdio_ext.h>
 #include <stddef.h>
 #include <stdlib.h>
+#include <limits.h>
 #include <malloc.h>
 #include <string.h>
 #include <strings.h>
@@ -44,12 +45,17 @@
 #include <sys/shm.h>
 #include <fcntl.h>
 
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+
 #include <netdb.h>
 #include <unistd.h>
 #include <syslog.h>
 #include <locale.h>
 #include <sys/syscall.h>
 #include <sys/auxv.h>
+#include <sys/prctl.h>
 
 #include <hybris/properties/properties.h>
 
@@ -68,8 +74,12 @@ static int locale_inited = 0;
 
 #define ANDROID_MUTEX_SHARED_MASK      0x2000
 #define ANDROID_COND_SHARED_MASK       0x0001
+#define ANDROID_COND_COUNTER_INCREMENT 0x0002
+#define ANDROID_COND_COUNTER_MASK      (~ANDROID_COND_SHARED_MASK)
 #define ANDROID_RWLOCKATTR_SHARED_MASK 0x0010
 
+#define ANDROID_COND_IS_SHARED(c)  (((c)->value & ANDROID_COND_SHARED_MASK) != 0)
+
 /* For the static initializer types */
 #define ANDROID_PTHREAD_MUTEX_INITIALIZER            0
 #define ANDROID_PTHREAD_RECURSIVE_MUTEX_INITIALIZER  0x4000
@@ -77,6 +87,8 @@ static int locale_inited = 0;
 #define ANDROID_PTHREAD_COND_INITIALIZER             0
 #define ANDROID_PTHREAD_RWLOCK_INITIALIZER           0
 
+#define MALI_HIST_DUMP_THREAD_NAME "mali-hist-dump"
+
 /* Debug */
 #include "logging.h"
 #define LOGD(message, ...) HYBRIS_DEBUG_LOG(HOOKS, message, ##__VA_ARGS__)
@@ -91,6 +103,11 @@ struct _hook {
     void *func;
 };
 
+/* pthread cond struct as done in Android */
+typedef struct {
+    int volatile value;
+} android_cond_t;
+
 /* Helpers */
 static int hybris_check_android_shared_mutex(unsigned int mutex_addr)
 {
@@ -113,9 +130,59 @@ static int hybris_check_android_shared_c
                     (cond_addr & ANDROID_COND_SHARED_MASK))
         return 1;
 
+    /* In case android is setting up cond_addr with a negative value,
+     * used for error control */
+    if (cond_addr > HYBRIS_SHM_MASK_TOP)
+        return 1;
+
+    return 0;
+}
+
+/* Based on Android's Bionic pthread implementation.
+ * This is just needed when we have a shared cond with Android */
+static int __android_pthread_cond_pulse(android_cond_t *cond, int counter)
+{
+    long flags;
+    int fret;
+
+    if (cond == NULL)
+        return EINVAL;
+
+    flags = (cond->value & ~ANDROID_COND_COUNTER_MASK);
+    for (;;) {
+        long oldval = cond->value;
+        long newval = 0;
+        /* In our case all we need to do is make sure the negative value
+         * is under our range, which is the last 0xF from SHM_MASK */
+        if (oldval < -12)
+            newval = ((oldval + ANDROID_COND_COUNTER_INCREMENT) &
+                            ANDROID_COND_COUNTER_MASK) | flags;
+        else
+            newval = ((oldval - ANDROID_COND_COUNTER_INCREMENT) &
+                            ANDROID_COND_COUNTER_MASK) | flags;
+        if (__sync_bool_compare_and_swap(&cond->value, oldval, newval))
+            break;
+    }
+
+    int pshared = cond->value & ANDROID_COND_SHARED_MASK;
+    fret = syscall(SYS_futex , &cond->value,
+                   pshared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, counter,
+                   NULL, NULL, NULL);
+    LOGD("futex based pthread_cond_*, value %d, counter %d, ret %d",
+                                            cond->value, counter, fret);
     return 0;
 }
 
+int android_pthread_cond_broadcast(android_cond_t *cond)
+{
+    return __android_pthread_cond_pulse(cond, INT_MAX);
+}
+
+int android_pthread_cond_signal(android_cond_t *cond)
+{
+    return __android_pthread_cond_pulse(cond, 1);
+}
+
 static void hybris_set_mutex_attr(unsigned int android_value, pthread_mutexattr_t *attr)
 {
     /* Init already sets as PTHREAD_MUTEX_NORMAL */
@@ -178,7 +245,6 @@ static void *my_memcpy(void *dst, const
 
 static size_t my_strlen(const char *s)
 {
-
     if (s == NULL)
         return -1;
 
@@ -187,7 +253,7 @@ static size_t my_strlen(const char *s)
 
 static pid_t my_gettid( void )
 {
-        return syscall( __NR_gettid );
+    return syscall(__NR_gettid);
 }
 
 /*
@@ -209,6 +275,14 @@ static int my_pthread_create(pthread_t *
     return pthread_create(thread, realattr, start_routine, arg);
 }
 
+static int my_pthread_kill(pthread_t thread, int sig)
+{
+    if (thread == 0)
+        return ESRCH;
+
+    return pthread_kill(thread, sig);
+}
+
 /*
  * pthread_attr_* functions
  *
@@ -515,6 +589,29 @@ static int my_pthread_mutex_lock_timeout
     return pthread_mutex_timedlock(realmutex, &tv);
 }
 
+static int my_pthread_mutex_timedlock(pthread_mutex_t *__mutex,
+                                      const struct timespec *__abs_timeout)
+{
+    if (!__mutex) {
+        LOGD("Null mutex lock, not unlocking.");
+        return 0;
+    }
+
+    unsigned int value = (*(unsigned int *) __mutex);
+    if (hybris_check_android_shared_mutex(value)) {
+        LOGD("Shared mutex with Android, not lock timeout np.");
+        return 0;
+    }
+
+    pthread_mutex_t *realmutex = (pthread_mutex_t *) value;
+    if (value <= ANDROID_TOP_ADDR_VALUE_MUTEX) {
+        realmutex = hybris_alloc_init_mutex(value);
+        *((int *)__mutex) = (int) realmutex;
+    }
+
+    return pthread_mutex_timedlock(realmutex, __abs_timeout);
+}
+
 static int my_pthread_mutexattr_setpshared(pthread_mutexattr_t *__attr,
                                            int pshared)
 {
@@ -585,8 +682,8 @@ static int my_pthread_cond_broadcast(pth
 {
     unsigned int value = (*(unsigned int *) cond);
     if (hybris_check_android_shared_cond(value)) {
-        LOGD("shared condition with Android, not broadcasting.");
-        return 0;
+        LOGD("Shared condition with Android, broadcasting with futex.");
+        return android_pthread_cond_broadcast((android_cond_t *) cond);
     }
 
     pthread_cond_t *realcond = (pthread_cond_t *) value;
@@ -606,8 +703,8 @@ static int my_pthread_cond_signal(pthrea
     unsigned int value = (*(unsigned int *) cond);
 
     if (hybris_check_android_shared_cond(value)) {
-        LOGD("Shared condition with Android, not signaling.");
-        return 0;
+        LOGD("Shared condition with Android, broadcasting with futex.");
+        return android_pthread_cond_signal((android_cond_t *) cond);
     }
 
     pthread_cond_t *realcond = (pthread_cond_t *) value;
@@ -731,6 +828,28 @@ static int my_pthread_cond_timedwait_rel
     return pthread_cond_timedwait(realcond, realmutex, &tv);
 }
 
+int my_pthread_setname_np(pthread_t thread, const char *name)
+{
+#ifdef MALI_QUIRKS
+    if (strcmp(name, MALI_HIST_DUMP_THREAD_NAME) == 0) {
+        HYBRIS_DEBUG_LOG(HOOKS, "%s: Found mali-hist-dump thread, killing it ...",
+                         __FUNCTION__);
+
+        if (thread != pthread_self()) {
+            HYBRIS_DEBUG_LOG(HOOKS, "%s: -> Failed, as calling thread is not mali-hist-dump itself",
+                             __FUNCTION__);
+            return;
+        }
+
+        pthread_exit(thread);
+
+        return;
+    }
+#endif
+
+    return pthread_setname_np(thread, name);
+}
+
 /*
  * pthread_rwlockattr_* functions
  *
@@ -898,6 +1017,18 @@ static int my_pthread_rwlock_unlock(pthr
     return pthread_rwlock_unlock(realrwlock);
 }
 
+#define min(X,Y) (((X) < (Y)) ? (X) : (Y))
+
+static pid_t my_pthread_gettid(pthread_t t)
+{
+    // glibc doesn't offer us a way to retrieve the thread id for a
+    // specific thread. However pthread_t is defined as unsigned
+    // long int and is the thread id so we can just copy it over
+    // into a pid_t.
+    pid_t tid;
+    memcpy(&tid, &t, min(sizeof(tid), sizeof(t)));
+    return tid;
+}
 
 static int my_set_errno(int oi_errno)
 {
@@ -1255,6 +1386,41 @@ static int my_readdir_r(DIR *dir, struct
     return res;
 }
 
+static inline void swap(void **a, void **b)
+{
+    void *tmp = *a;
+    *a = *b;
+    *b = tmp;
+}
+
+static int my_getaddrinfo(const char *hostname, const char *servname,
+    const struct addrinfo *hints, struct addrinfo **res)
+{
+    // make a local copy of hints
+    struct addrinfo *fixed_hints = (struct addrinfo*)malloc(sizeof(struct addrinfo));
+    memcpy(fixed_hints, hints, sizeof(struct addrinfo));
+    // fix bionic -> glibc missmatch
+    swap((void**)&(fixed_hints->ai_canonname), (void**)&(fixed_hints->ai_addr));
+    // do glibc getaddrinfo
+    int result = getaddrinfo(hostname, servname, fixed_hints, res);
+    // release the copy of hints
+    free(fixed_hints);
+    // fix bionic <- glibc missmatch
+    struct addrinfo *it = *res;
+    while(NULL != it)
+    {
+        swap((void**)&(it->ai_canonname), (void**)&(it->ai_addr));
+        it = it->ai_next;
+    }
+    return result;
+}
+
+static void my_freeaddrinfo(struct addrinfo *__ai)
+{
+    swap((void**)&(__ai->ai_canonname), (void**)&(__ai->ai_addr));
+    freeaddrinfo(__ai);
+}
+
 extern long my_sysconf(int name);
 
 FP_ATTRIB static double my_strtod(const char *nptr, char **endptr)
@@ -1267,6 +1433,51 @@ FP_ATTRIB static double my_strtod(const
 	return strtod_l(nptr, endptr, hybris_locale);
 }
 
+static int __my_system_property_read(const void *pi, char *name, char *value)
+{
+    return property_get(name, value, NULL);
+}
+
+static int __my_system_property_foreach(void (*propfn)(const void *pi, void *cookie), void *cookie)
+{
+    return 0;
+}
+
+static const void *__my_system_property_find(const char *name)
+{
+    return NULL;
+}
+
+static unsigned int __my_system_property_serial(const void *pi)
+{
+    return 0;
+}
+
+static int __my_system_property_wait(const void *pi)
+{
+    return 0;
+}
+
+static int __my_system_property_update(void *pi, const char *value, unsigned int len)
+{
+    return 0;
+}
+
+static int __my_system_property_add(const char *name, unsigned int namelen, const char *value, unsigned int valuelen)
+{
+    return 0;
+}
+
+static unsigned int __my_system_property_wait_any(unsigned int serial)
+{
+    return 0;
+}
+
+static const void *__my_system_property_find_nth(unsigned n)
+{
+    return NULL;
+}
+
 extern int __cxa_atexit(void (*)(void*), void*, void*);
 extern void __cxa_finalize(void * d);
 
@@ -1276,10 +1487,10 @@ struct open_redirect {
 };
 
 struct open_redirect open_redirects[] = {
-	{ "/dev/log/main", "/dev/log_main" },
-	{ "/dev/log/radio", "/dev/log_radio" },
-	{ "/dev/log/system", "/dev/log_system" },
-	{ "/dev/log/events", "/dev/log_events" },
+	{ "/dev/log/main", "/dev/alog/main" },
+	{ "/dev/log/radio", "/dev/alog/radio" },
+	{ "/dev/log/system", "/dev/alog/system" },
+	{ "/dev/log/events", "/dev/alog/events" },
 	{ NULL, NULL }
 };
 
@@ -1329,6 +1540,30 @@ void *__get_tls_hooks()
   return tls_hooks;
 }
 
+int my_prctl(int option, unsigned long arg2, unsigned long arg3,
+             unsigned long arg4, unsigned long arg5)
+{
+#ifdef MALI_QUIRKS
+    if (option == PR_SET_NAME) {
+        char *name = (char*) arg2;
+
+        if (strcmp(name, MALI_HIST_DUMP_THREAD_NAME) == 0) {
+
+            // This can only work because prctl with PR_SET_NAME
+            // can be only called for the current thread and not
+            // for another thread so we can safely pause things.
+
+            HYBRIS_DEBUG_LOG(HOOKS, "%s: Found mali-hist-dump, killing thread ...",
+                             __FUNCTION__);
+
+            pthread_exit(NULL);
+        }
+    }
+#endif
+
+    return prctl(option, arg2, arg3, arg4, arg5);
+}
+
 static struct _hook hooks[] = {
     {"property_get", property_get },
     {"property_set", property_set },
@@ -1354,6 +1589,7 @@ static struct _hook hooks[] = {
     {"memmove",memmove},
     {"memset",memset},
     {"memmem",memmem},
+    {"getlogin", getlogin},
     //  {"memswap",memswap},
     {"index",index},
     {"rindex",rindex},
@@ -1395,6 +1631,8 @@ static struct _hook hooks[] = {
     {"index",index},
     {"rindex",rindex},
     {"strcasecmp",strcasecmp},
+    {"__sprintf_chk", __sprintf_chk},
+    {"__snprintf_chk", __snprintf_chk},
     {"strncasecmp",strncasecmp},
     /* dirent.h */
     {"opendir", opendir},
@@ -1405,7 +1643,7 @@ static struct _hook hooks[] = {
     {"getpid", getpid},
     {"pthread_atfork", pthread_atfork},
     {"pthread_create", my_pthread_create},
-    {"pthread_kill", pthread_kill},
+    {"pthread_kill", my_pthread_kill},
     {"pthread_exit", pthread_exit},
     {"pthread_join", pthread_join},
     {"pthread_detach", pthread_detach},
@@ -1419,6 +1657,7 @@ static struct _hook hooks[] = {
     {"pthread_mutex_unlock", my_pthread_mutex_unlock},
     {"pthread_mutex_trylock", my_pthread_mutex_trylock},
     {"pthread_mutex_lock_timeout_np", my_pthread_mutex_lock_timeout_np},
+    {"pthread_mutex_timedlock", my_pthread_mutex_timedlock},
     {"pthread_mutexattr_init", pthread_mutexattr_init},
     {"pthread_mutexattr_destroy", pthread_mutexattr_destroy},
     {"pthread_mutexattr_gettype", pthread_mutexattr_gettype},
@@ -1429,6 +1668,8 @@ static struct _hook hooks[] = {
     {"pthread_condattr_getpshared", pthread_condattr_getpshared},
     {"pthread_condattr_setpshared", pthread_condattr_setpshared},
     {"pthread_condattr_destroy", pthread_condattr_destroy},
+    {"pthread_condattr_getclock", pthread_condattr_getclock},
+    {"pthread_condattr_setclock", pthread_condattr_setclock},
     {"pthread_cond_init", my_pthread_cond_init},
     {"pthread_cond_destroy", my_pthread_cond_destroy},
     {"pthread_cond_broadcast", my_pthread_cond_broadcast},
@@ -1439,7 +1680,7 @@ static struct _hook hooks[] = {
     {"pthread_cond_timedwait_monotonic_np", my_pthread_cond_timedwait},
     {"pthread_cond_timedwait_relative_np", my_pthread_cond_timedwait_relative_np},
     {"pthread_key_delete", pthread_key_delete},
-    {"pthread_setname_np", pthread_setname_np},
+    {"pthread_setname_np", my_pthread_setname_np},
     {"pthread_once", pthread_once},
     {"pthread_key_create", pthread_key_create},
     {"pthread_setspecific", pthread_setspecific},
@@ -1461,7 +1702,7 @@ static struct _hook hooks[] = {
     {"pthread_attr_setguardsize", my_pthread_attr_setguardsize},
     {"pthread_attr_getguardsize", my_pthread_attr_getguardsize},
     {"pthread_attr_setscope", my_pthread_attr_setscope},
-    {"pthread_attr_setscope", my_pthread_attr_getscope},
+    {"pthread_attr_getscope", my_pthread_attr_getscope},
     {"pthread_getattr_np", my_pthread_getattr_np},
     {"pthread_rwlockattr_init", my_pthread_rwlockattr_init},
     {"pthread_rwlockattr_destroy", my_pthread_rwlockattr_destroy},
@@ -1476,6 +1717,9 @@ static struct _hook hooks[] = {
     {"pthread_rwlock_trywrlock", my_pthread_rwlock_trywrlock},
     {"pthread_rwlock_timedrdlock", my_pthread_rwlock_timedrdlock},
     {"pthread_rwlock_timedwrlock", my_pthread_rwlock_timedwrlock},
+    /* bionic-only pthread */
+    {"__pthread_gettid", my_pthread_gettid},
+    {"pthread_gettid_np", my_pthread_gettid},
     /* stdio.h */
     {"__isthreaded", &__my_isthreaded},
     {"__sF", &my_sF},
@@ -1536,7 +1780,8 @@ static struct _hook hooks[] = {
     {"__errno", __errno_location},
     {"__set_errno", my_set_errno},
     /* net specifics, to avoid __res_get_state */
-    {"getaddrinfo", getaddrinfo},
+    {"getaddrinfo", my_getaddrinfo},
+    {"freeaddrinfo", my_freeaddrinfo},
     {"gethostbyaddr", gethostbyaddr},
     {"gethostbyname", gethostbyname},
     {"gethostbyname2", gethostbyname2},
@@ -1575,6 +1820,9 @@ static struct _hook hooks[] = {
     {"timer_gettime", timer_gettime},
     {"timer_delete", timer_delete},
     {"timer_getoverrun", timer_getoverrun},
+    {"localtime", localtime},
+    {"localtime_r", localtime_r},
+    {"gmtime", gmtime},
     {"abort", abort},
     {"writev", writev},
     /* unistd.h */
@@ -1583,31 +1831,64 @@ static struct _hook hooks[] = {
     {"getgrgid", getgrgid},
     {"__cxa_atexit", __cxa_atexit},
     {"__cxa_finalize", __cxa_finalize},
-    {NULL, NULL},
+    {"__system_property_read", __my_system_property_read},
+    {"__system_property_set", property_set},
+    {"__system_property_foreach", __my_system_property_foreach},
+    {"__system_property_find", __my_system_property_find},
+    {"__system_property_serial", __my_system_property_serial},
+    {"__system_property_wait", __my_system_property_wait},
+    {"__system_property_update", __my_system_property_update},
+    {"__system_property_add", __my_system_property_add},
+    {"__system_property_wait_any", __my_system_property_wait_any},
+    {"__system_property_find_nth", __my_system_property_find_nth},
+    /* sys/prctl.h */
+    {"prctl", my_prctl},
 };
 
+static int hook_cmp(const void *a, const void *b)
+{
+    return strcmp(((struct _hook*)a)->name, ((struct _hook*)b)->name);
+}
+
 void *get_hooked_symbol(char *sym)
 {
-    struct _hook *ptr = &hooks[0];
     static int counter = -1;
+    static int sorted = 0;
+    const int nhooks = sizeof(hooks) / sizeof(hooks[0]);
+    void *found = NULL;
+    struct _hook key;
 
-    while (ptr->name != NULL)
+    if (!sorted)
     {
-        if (strcmp(sym, ptr->name) == 0){
-            return ptr->func;
-        }
-        ptr++;
+        qsort(hooks, nhooks, sizeof(hooks[0]), hook_cmp);
+        sorted = 1;
     }
-    if (strstr(sym, "pthread") != NULL)
+
+    key.name = sym;
+    found = bsearch(&key, hooks, nhooks, sizeof(hooks[0]), hook_cmp);
+    if (found != NULL)
+    {
+        LOGD("Found hook for symbol %s", sym);
+        return ((struct _hook*)found)->func;
+    }
+
+    if (strncmp(sym, "pthread", 7) == 0 ||
+        strncmp(sym, "__pthread", 9) == 0)
     {
         /* safe */
         if (strcmp(sym, "pthread_sigmask") == 0)
            return NULL;
         /* not safe */
         counter--;
-        LOGD("%s %i\n", sym, counter);
+        // If you're experiencing a crash later on check the address of the
+        // function pointer being call. If it matches the printed counter
+        // value here then you can easily find out which symbol is missing.
+        LOGD("Missing hook for pthread symbol %s (counter %i)\n", sym, counter);
         return (void *) counter;
     }
+
+    LOGD("Could not find a hook for symbol %s", sym);
+
     return NULL;
 }
 
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/hooks_shm.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/hooks_shm.c
@@ -123,7 +123,9 @@ static void _hybris_shm_init()
         else {
             LOGD("Creating a new shared memory segment.");
 
-            _hybris_shm_fd = shm_open(HYBRIS_SHM_PATH, O_RDWR | O_CREAT, 0660);
+            mode_t pumask = umask(0);
+            _hybris_shm_fd = shm_open(HYBRIS_SHM_PATH, O_RDWR | O_CREAT, 0666);
+            umask(pumask);
             if (_hybris_shm_fd >= 0) {
                 ftruncate( _hybris_shm_fd, size_to_map );
                 /* Map the memory object */
@@ -171,11 +173,12 @@ static void _hybris_shm_extend_region()
 
  /*
   * Determine if the pointer that has been extracted by hybris is
-  * pointing to an address in the shared memory
+  * pointing to an address in the shared memory.
   */
 int hybris_is_pointer_in_shm(void *ptr)
 {
-    if ((unsigned int)ptr >= HYBRIS_SHM_MASK)
+    if (((unsigned int) ptr >= HYBRIS_SHM_MASK) &&
+                    ((unsigned int) ptr <= HYBRIS_SHM_MASK_TOP))
         return 1;
 
     return 0;
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/hooks_shm.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/hooks_shm.h
@@ -20,6 +20,9 @@
 
 #include <stddef.h>
 
+/* Leave space to workaround the issue that Android might pass negative int values */
+#define HYBRIS_SHM_MASK_TOP 0xFFFFFFF0UL
+
 typedef unsigned int hybris_shm_pointer_t;
 
 /* 
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/jb/dlfcn.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/jb/dlfcn.c
@@ -78,7 +78,7 @@ const char *android_dlerror(void)
 void *android_dlsym(void *handle, const char *symbol)
 {
     soinfo *found;
-    Elf32_Sym *sym;
+    Elf_Sym *sym;
     unsigned bind;
 
     pthread_mutex_lock(&dl_lock);
@@ -142,7 +142,7 @@ int android_dladdr(const void *addr, Dl_
         info->dli_fbase = (void*)si->base;
 
         /* Determine if any symbol in the library contains the specified address */
-        Elf32_Sym *sym = find_containing_symbol(addr, si);
+        Elf_Sym *sym = find_containing_symbol(addr, si);
 
         if(sym != NULL) {
             info->dli_sname = si->strtab + sym->st_name;
@@ -171,7 +171,7 @@ int android_dl_iterate_phdr(int (*cb)(st
 //                     0000000 00011111 111112 22222222 2333333 333344444444445555555
 //                     0123456 78901234 567890 12345678 9012345 678901234567890123456
 #define ANDROID_LIBDL_STRTAB \
-                      "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0dl_iterate_phdr\0"
+                      "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0dl_unwind_find_exidx\0"
 
 _Unwind_Ptr android_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount);
 
@@ -191,7 +191,7 @@ _Unwind_Ptr android_dl_unwind_find_exidx
 #endif
 
 
-static Elf32_Sym libdl_symtab[] = {
+static Elf_Sym libdl_symtab[] = {
       // total length of libdl_info.strtab, including trailing 0
       // This is actually the the STH_UNDEF entry. Technically, it's
       // supposed to have st_name == 0, but instead, it points to an index
@@ -199,44 +199,42 @@ static Elf32_Sym libdl_symtab[] = {
     { st_name: sizeof(ANDROID_LIBDL_STRTAB) - 1,
     },
     { st_name: 0,   // starting index of the name in libdl_info.strtab
-      st_value: (Elf32_Addr) &android_dlopen,
+      st_value: (Elf_Addr) &android_dlopen,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
     { st_name: 7,
-      st_value: (Elf32_Addr) &android_dlclose,
+      st_value: (Elf_Addr) &android_dlclose,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
     { st_name: 15,
-      st_value: (Elf32_Addr) &android_dlsym,
+      st_value: (Elf_Addr) &android_dlsym,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
     { st_name: 21,
-      st_value: (Elf32_Addr) &android_dlerror,
+      st_value: (Elf_Addr) &android_dlerror,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
     { st_name: 29,
-      st_value: (Elf32_Addr) &android_dladdr,
+      st_value: (Elf_Addr) &android_dladdr,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
-#ifdef ANDROID_ARM_LINKER
     { st_name: 36,
-      st_value: (Elf32_Addr) &android_dl_unwind_find_exidx,
+      st_value: (Elf_Addr) &android_dl_iterate_phdr,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
-    { st_name: 57,
-#else
-    { st_name: 36,
-#endif
-      st_value: (Elf32_Addr) &android_dl_iterate_phdr,
+#ifdef ANDROID_ARM_LINKER
+    { st_name: 52,
+      st_value: (Elf_Addr) &android_dl_unwind_find_exidx,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
+#endif
 };
 
 /* Fake out a hash table with a single bucket.
@@ -273,12 +271,8 @@ soinfo libdl_info = {
     symtab: libdl_symtab,
 
     refcount: 1,
-    nbucket: 1,
-#if defined(ANDROID_ARM_LINKER)
-    nchain: 8,
-#else
-    nchain: 7,
-#endif
+    nbucket: sizeof(libdl_buckets)/sizeof(unsigned),
+    nchain: sizeof(libdl_chains)/sizeof(unsigned),
     bucket: libdl_buckets,
     chain: libdl_chains,
 };
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/jb/linker.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/jb/linker.c
@@ -380,10 +380,10 @@ android_dl_iterate_phdr(int (*cb)(struct
     return rv;
 }
 
-static Elf32_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name)
+static Elf_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name)
 {
-    Elf32_Sym *s;
-    Elf32_Sym *symtab = si->symtab;
+    Elf_Sym *s;
+    Elf_Sym *symtab = si->symtab;
     const char *strtab = si->strtab;
     unsigned n;
 
@@ -425,11 +425,11 @@ static unsigned elfhash(const char *_nam
     return h;
 }
 
-static Elf32_Sym *
+static Elf_Sym *
 _do_lookup(soinfo *si, const char *name, unsigned *base)
 {
     unsigned elf_hash = elfhash(name);
-    Elf32_Sym *s;
+    Elf_Sym *s;
     unsigned *d;
     soinfo *lsi = si;
     int i;
@@ -501,17 +501,17 @@ done:
 /* This is used by dl_sym().  It performs symbol lookup only within the
    specified soinfo object and not in any of its dependencies.
  */
-Elf32_Sym *lookup_in_library(soinfo *si, const char *name)
+Elf_Sym *lookup_in_library(soinfo *si, const char *name)
 {
     return _elf_lookup(si, elfhash(name), name);
 }
 
 /* This is used by dl_sym().  It performs a global symbol lookup.
  */
-Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start)
+Elf_Sym *lookup(const char *name, soinfo **found, soinfo *start)
 {
     unsigned elf_hash = elfhash(name);
-    Elf32_Sym *s = NULL;
+    Elf_Sym *s = NULL;
     soinfo *si;
 
     if(start == NULL) {
@@ -552,7 +552,7 @@ soinfo *find_containing_library(const vo
     return NULL;
 }
 
-Elf32_Sym *find_containing_symbol(const void *addr, soinfo *si)
+Elf_Sym *find_containing_symbol(const void *addr, soinfo *si)
 {
     unsigned int i;
     unsigned soaddr = (unsigned)addr - si->base;
@@ -560,7 +560,7 @@ Elf32_Sym *find_containing_symbol(const
     /* Search the library's symbol table for any defined symbol which
      * contains this address */
     for(i=0; i<si->nchain; i++) {
-        Elf32_Sym *sym = &si->symtab[i];
+        Elf_Sym *sym = &si->symtab[i];
 
         if(sym->st_shndx != SHN_UNDEF &&
            soaddr >= sym->st_value &&
@@ -575,7 +575,7 @@ Elf32_Sym *find_containing_symbol(const
 #if 0
 static void dump(soinfo *si)
 {
-    Elf32_Sym *s = si->symtab;
+    Elf_Sym *s = si->symtab;
     unsigned n;
 
     for(n = 0; n < si->nchain; n++) {
@@ -704,7 +704,7 @@ is_prelinked(int fd, const char *name)
 static int
 verify_elf_object(void *base, const char *name)
 {
-    Elf32_Ehdr *hdr = (Elf32_Ehdr *) base;
+    Elf_Ehdr *hdr = (Elf_Ehdr *) base;
 
     if (hdr->e_ident[EI_MAG0] != ELFMAG0) return -1;
     if (hdr->e_ident[EI_MAG1] != ELFMAG1) return -1;
@@ -749,8 +749,8 @@ get_lib_extents(int fd, const char *name
     unsigned min_vaddr = 0xffffffff;
     unsigned max_vaddr = 0;
     unsigned char *_hdr = (unsigned char *)__hdr;
-    Elf32_Ehdr *ehdr = (Elf32_Ehdr *)_hdr;
-    Elf32_Phdr *phdr;
+    Elf_Ehdr *ehdr = (Elf_Ehdr *)_hdr;
+    Elf_Phdr *phdr;
     int cnt;
 
     TRACE("[ %5d Computing extents for '%s'. ]\n", pid, name);
@@ -769,7 +769,7 @@ get_lib_extents(int fd, const char *name
         TRACE("[ %5d - Non-prelinked library '%s' found. ]\n", pid, name);
     }
 
-    phdr = (Elf32_Phdr *)(_hdr + ehdr->e_phoff);
+    phdr = (Elf_Phdr *)(_hdr + ehdr->e_phoff);
 
     /* find the min/max p_vaddrs from all the PT_LOAD segments so we can
      * get the range. */
@@ -884,12 +884,12 @@ err:
 static int
 load_segments(int fd, void *header, soinfo *si)
 {
-    Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header;
-    Elf32_Phdr *phdr = (Elf32_Phdr *)((unsigned char *)header + ehdr->e_phoff);
-    Elf32_Addr base = (Elf32_Addr) si->base;
+    Elf_Ehdr *ehdr = (Elf_Ehdr *)header;
+    Elf_Phdr *phdr = (Elf_Phdr *)((unsigned char *)header + ehdr->e_phoff);
+    Elf_Addr base = (Elf_Addr) si->base;
     int cnt;
     unsigned len;
-    Elf32_Addr tmp;
+    Elf_Addr tmp;
     unsigned char *pbase;
     unsigned char *extra_base;
     unsigned extra_len;
@@ -955,7 +955,7 @@ load_segments(int fd, void *header, soin
              *                  |                     |
              *                 _+---------------------+  page boundary
              */
-            tmp = (Elf32_Addr)(((unsigned)pbase + len + PAGE_SIZE - 1) &
+            tmp = (Elf_Addr)(((unsigned)pbase + len + PAGE_SIZE - 1) &
                                     (~PAGE_MASK));
             if (tmp < (base + phdr->p_vaddr + phdr->p_memsz)) {
                 extra_len = base + phdr->p_vaddr + phdr->p_memsz - tmp;
@@ -1019,7 +1019,7 @@ load_segments(int fd, void *header, soin
                        phdr->p_vaddr, phdr->p_memsz);
                 goto fail;
             }
-            si->gnu_relro_start = (Elf32_Addr) (base + phdr->p_vaddr);
+            si->gnu_relro_start = (Elf_Addr) (base + phdr->p_vaddr);
             si->gnu_relro_len = (unsigned) phdr->p_memsz;
         } else {
 #ifdef ANDROID_ARM_LINKER
@@ -1066,11 +1066,11 @@ fail:
  */
 #if 0
 static unsigned
-get_wr_offset(int fd, const char *name, Elf32_Ehdr *ehdr)
+get_wr_offset(int fd, const char *name, Elf_Ehdr *ehdr)
 {
-    Elf32_Shdr *shdr_start;
-    Elf32_Shdr *shdr;
-    int shdr_sz = ehdr->e_shnum * sizeof(Elf32_Shdr);
+    Elf_Shdr *shdr_start;
+    Elf_Shdr *shdr;
+    int shdr_sz = ehdr->e_shnum * sizeof(Elf_Shdr);
     int cnt;
     unsigned wr_offset = 0xffffffff;
 
@@ -1103,7 +1103,7 @@ load_library(const char *name)
     unsigned req_base;
     const char *bname;
     soinfo *si = NULL;
-    Elf32_Ehdr *hdr;
+    Elf_Ehdr *hdr;
 
     if(fd == -1) {
         DL_ERR("Library '%s' not found", name);
@@ -1160,8 +1160,8 @@ load_library(const char *name)
 
     /* this might not be right. Technically, we don't even need this info
      * once we go through 'load_segments'. */
-    hdr = (Elf32_Ehdr *)si->base;
-    si->phdr = (Elf32_Phdr *)((unsigned char *)si->base + hdr->e_phoff);
+    hdr = (Elf_Ehdr *)si->base;
+    si->phdr = (Elf_Phdr *)((unsigned char *)si->base + hdr->e_phoff);
     si->phnum = hdr->e_phnum;
     /**/
 
@@ -1260,7 +1260,7 @@ unsigned unload_library(soinfo *si)
          * in link_image. This is needed to undo the DT_NEEDED hack below.
          */
         if ((si->gnu_relro_start != 0) && (si->gnu_relro_len != 0)) {
-            Elf32_Addr start = (si->gnu_relro_start & ~PAGE_MASK);
+            Elf_Addr start = (si->gnu_relro_start & ~PAGE_MASK);
             unsigned len = (si->gnu_relro_start - start) + si->gnu_relro_len;
             if (mprotect((void *) start, len, PROT_READ | PROT_WRITE) < 0)
                 DL_ERR("%5d %s: could not undo GNU_RELRO protections. "
@@ -1303,16 +1303,16 @@ unsigned unload_library(soinfo *si)
 }
 
 /* TODO: don't use unsigned for addrs below. It works, but is not
- * ideal. They should probably be either uint32_t, Elf32_Addr, or unsigned
+ * ideal. They should probably be either uint32_t, Elf_Addr, or unsigned
  * long.
  */
-static int reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count)
+static int reloc_library(soinfo *si, Elf_Rel *rel, unsigned count)
 {
-    Elf32_Sym *symtab = si->symtab;
+    Elf_Sym *symtab = si->symtab;
     const char *strtab = si->strtab;
-    Elf32_Sym *s;
+    Elf_Sym *s;
     unsigned base;
-    Elf32_Rel *start = rel;
+    Elf_Rel *start = rel;
     unsigned idx;
 
     for (idx = 0; idx < count; ++idx) {
@@ -1711,7 +1711,7 @@ static int nullify_closed_stdio (void)
 static int link_image(soinfo *si, unsigned wr_offset)
 {
     unsigned *d;
-    Elf32_Phdr *phdr = si->phdr;
+    Elf_Phdr *phdr = si->phdr;
     int phnum = si->phnum;
 
     INFO("[ %5d linking %s ]\n", pid, si->name);
@@ -1794,7 +1794,7 @@ static int link_image(soinfo *si, unsign
                            phdr->p_vaddr, phdr->p_memsz);
                     goto fail;
                 }
-                si->gnu_relro_start = (Elf32_Addr) (si->base + phdr->p_vaddr);
+                si->gnu_relro_start = (Elf_Addr) (si->base + phdr->p_vaddr);
                 si->gnu_relro_len = (unsigned) phdr->p_memsz;
             }
         }
@@ -1821,7 +1821,7 @@ static int link_image(soinfo *si, unsign
             si->strtab = (const char *) (si->base + *d);
             break;
         case DT_SYMTAB:
-            si->symtab = (Elf32_Sym *) (si->base + *d);
+            si->symtab = (Elf_Sym *) (si->base + *d);
             break;
         case DT_PLTREL:
             if(*d != DT_REL) {
@@ -1830,13 +1830,13 @@ static int link_image(soinfo *si, unsign
             }
             break;
         case DT_JMPREL:
-            si->plt_rel = (Elf32_Rel*) (si->base + *d);
+            si->plt_rel = (Elf_Rel*) (si->base + *d);
             break;
         case DT_PLTRELSZ:
             si->plt_rel_count = *d / 8;
             break;
         case DT_REL:
-            si->rel = (Elf32_Rel*) (si->base + *d);
+            si->rel = (Elf_Rel*) (si->base + *d);
             break;
         case DT_RELSZ:
             si->rel_count = *d / 8;
@@ -1868,7 +1868,7 @@ static int link_image(soinfo *si, unsign
                   pid, si->name, si->init_array);
             break;
         case DT_INIT_ARRAYSZ:
-            si->init_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
+            si->init_array_count = ((unsigned)*d) / sizeof(Elf_Addr);
             break;
         case DT_FINI_ARRAY:
             si->fini_array = (unsigned *)(si->base + *d);
@@ -1876,7 +1876,7 @@ static int link_image(soinfo *si, unsign
                   pid, si->name, si->fini_array);
             break;
         case DT_FINI_ARRAYSZ:
-            si->fini_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
+            si->fini_array_count = ((unsigned)*d) / sizeof(Elf_Addr);
             break;
         case DT_PREINIT_ARRAY:
             si->preinit_array = (unsigned *)(si->base + *d);
@@ -1884,7 +1884,7 @@ static int link_image(soinfo *si, unsign
                   pid, si->name, si->preinit_array);
             break;
         case DT_PREINIT_ARRAYSZ:
-            si->preinit_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
+            si->preinit_array_count = ((unsigned)*d) / sizeof(Elf_Addr);
             break;
         case DT_TEXTREL:
             /* TODO: make use of this. */
@@ -1986,7 +1986,7 @@ static int link_image(soinfo *si, unsign
 #endif
 
     if (si->gnu_relro_start != 0 && si->gnu_relro_len != 0) {
-        Elf32_Addr start = (si->gnu_relro_start & ~PAGE_MASK);
+        Elf_Addr start = (si->gnu_relro_start & ~PAGE_MASK);
         unsigned len = (si->gnu_relro_start - start) + si->gnu_relro_len;
         if (mprotect((void *) start, len, PROT_READ) < 0) {
             DL_ERR("%5d GNU_RELRO mprotect of library '%s' failed: %d (%s)\n",
@@ -2169,7 +2169,7 @@ sanitize:
     while(vecs[0] != 0){
         switch(vecs[0]){
         case AT_PHDR:
-            si->phdr = (Elf32_Phdr*) vecs[1];
+            si->phdr = (Elf_Phdr*) vecs[1];
             break;
         case AT_PHNUM:
             si->phnum = (int) vecs[1];
@@ -2189,7 +2189,7 @@ sanitize:
     si->base = 0;
     for ( nn = 0; nn < si->phnum; nn++ ) {
         if (si->phdr[nn].p_type == PT_PHDR) {
-            si->base = (Elf32_Addr) si->phdr - si->phdr[nn].p_vaddr;
+            si->base = (Elf_Addr) si->phdr - si->phdr[nn].p_vaddr;
             break;
         }
     }
@@ -2302,9 +2302,9 @@ static unsigned find_linker_base(unsigne
  */
 unsigned __linker_init(unsigned **elfdata) {
     unsigned linker_addr = find_linker_base(elfdata);
-    Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) linker_addr;
-    Elf32_Phdr *phdr =
-        (Elf32_Phdr *)((unsigned char *) linker_addr + elf_hdr->e_phoff);
+    Elf_Ehdr *elf_hdr = (Elf_Ehdr *) linker_addr;
+    Elf_Phdr *phdr =
+        (Elf_Phdr *)((unsigned char *) linker_addr + elf_hdr->e_phoff);
 
     soinfo linker_so;
     memset(&linker_so, 0, sizeof(soinfo));
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/jb/linker.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/jb/linker.h
@@ -38,6 +38,26 @@
 #define PAGE_SIZE 4096
 #define PAGE_MASK 4095
 
+#if defined(__x86_64__)
+typedef Elf64_Ehdr Elf_Ehdr;
+typedef Elf64_Shdr Elf_Shdr;
+typedef Elf64_Sym  Elf_Sym;
+typedef Elf64_Addr Elf_Addr;
+typedef Elf64_Phdr Elf_Phdr;
+typedef Elf64_Half Elf_Half;
+typedef Elf64_Rel  Elf_Rel;
+typedef Elf64_Rela Elf_Rela;
+#else
+typedef Elf32_Ehdr Elf_Ehdr;
+typedef Elf32_Shdr Elf_Shdr;
+typedef Elf32_Sym  Elf_Sym;
+typedef Elf32_Addr Elf_Addr;
+typedef Elf32_Phdr Elf_Phdr;
+typedef Elf32_Half Elf_Half;
+typedef Elf32_Rel  Elf_Rel;
+typedef Elf32_Rela Elf_Rela;
+#endif
+
 void debugger_init();
 const char *addr_to_name(unsigned addr);
 
@@ -55,10 +75,10 @@ struct link_map
 /* needed for dl_iterate_phdr to be passed to the callbacks provided */
 struct dl_phdr_info
 {
-    Elf32_Addr dlpi_addr;
+    Elf_Addr dlpi_addr;
     const char *dlpi_name;
-    const Elf32_Phdr *dlpi_phdr;
-    Elf32_Half dlpi_phnum;
+    const Elf_Phdr *dlpi_phdr;
+    Elf_Half dlpi_phnum;
 };
 
 
@@ -90,7 +110,7 @@ typedef struct soinfo soinfo;
 struct soinfo
 {
     const char name[SOINFO_NAME_LEN];
-    Elf32_Phdr *phdr;
+    Elf_Phdr *phdr;
     int phnum;
     unsigned entry;
     unsigned base;
@@ -107,7 +127,7 @@ struct soinfo
     unsigned flags;
 
     const char *strtab;
-    Elf32_Sym *symtab;
+    Elf_Sym *symtab;
 
     unsigned nbucket;
     unsigned nchain;
@@ -116,10 +136,10 @@ struct soinfo
 
     unsigned *plt_got;
 
-    Elf32_Rel *plt_rel;
+    Elf_Rel *plt_rel;
     unsigned plt_rel_count;
 
-    Elf32_Rel *rel;
+    Elf_Rel *rel;
     unsigned rel_count;
 
     unsigned *preinit_array;
@@ -144,7 +164,7 @@ struct soinfo
 
     int constructors_called;
 
-    Elf32_Addr gnu_relro_start;
+    Elf_Addr gnu_relro_start;
     unsigned gnu_relro_len;
 
 };
@@ -202,18 +222,17 @@ extern soinfo libdl_info;
 
 soinfo *find_library(const char *name);
 unsigned unload_library(soinfo *si);
-Elf32_Sym *lookup_in_library(soinfo *si, const char *name);
-Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start);
+Elf_Sym *lookup_in_library(soinfo *si, const char *name);
+Elf_Sym *lookup(const char *name, soinfo **found, soinfo *start);
 soinfo *find_containing_library(const void *addr);
-Elf32_Sym *find_containing_symbol(const void *addr, soinfo *si);
+Elf_Sym *find_containing_symbol(const void *addr, soinfo *si);
 const char *linker_get_error(void);
 void call_constructors_recursive(soinfo *si);
 
+int dl_iterate_phdr(int (*cb)(struct dl_phdr_info *, size_t, void *), void *);
 #ifdef ANDROID_ARM_LINKER 
 typedef long unsigned int *_Unwind_Ptr;
 _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount);
-#elif defined(ANDROID_X86_LINKER)
-int dl_iterate_phdr(int (*cb)(struct dl_phdr_info *, size_t, void *), void *);
 #endif
 
 #endif
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/common/jb/linker_format.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/common/jb/linker_format.c
@@ -268,7 +268,7 @@ static int log_vprint(int prio, const ch
     result = vformat_buffer(buf, sizeof buf, fmt, args);
 
     if (log_fd < 0) {
-        log_fd = open("/dev/log/main", O_WRONLY);
+        log_fd = open("/dev/alog/main", O_WRONLY);
         if (log_fd < 0) {
             log_fd = fileno(stdout); // kernel doesn't have android log
             return result;
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/configure.ac
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/configure.ac
@@ -73,6 +73,13 @@ AC_ARG_ENABLE(wayland_serverside_buffers
   [wayland_serverside_buffers=yes])
 AM_CONDITIONAL( [WANT_WL_SERVERSIDE_BUFFERS], [test x"$wayland_serverside_buffers" = x"yes"])
 
+AC_ARG_ENABLE(property_cache,
+  [  --enable-property-cache      Enable runtime android property cache (default=disabled)],
+  [property_cache=$enableval],
+  [property_cache=no])
+AM_CONDITIONAL( [WANT_RUNTIME_PROPERTY_CACHE], [test x"$property_cache" = x"yes"])
+
+
 AC_ARG_ENABLE(arch,
   [  --enable-arch[=arch]     Compile specific CPU target(default=arm)
                               arm: compile for ARM
@@ -114,7 +121,10 @@ AC_ARG_WITH(android-headers,
     AS_IF([test -f $withval/libnfc-nxp/phLibNfc.h], [ANDROID_HEADERS_CFLAGS="-I$withval -I$withval/libnfc-nxp"],[ANDROID_HEADERS_CFLAGS="-I$withval"])
     AC_SUBST([ANDROID_HEADERS_CFLAGS])
   ],
-  [ PKG_CHECK_MODULES(ANDROID_HEADERS, android-headers,, exit) ]
+  [
+    PKG_CHECK_MODULES(ANDROID_HEADERS, android-headers,, exit)
+    AM_CONDITIONAL([HAS_LIBNFC_NXP_HEADERS], [false])
+  ]
 )
 CPPFLAGS="$CPPFLAGS $ANDROID_HEADERS_CFLAGS"
 
@@ -177,6 +187,11 @@ AM_CONDITIONAL([HAS_ANDROID_4_1_0], [tes
 AM_CONDITIONAL([HAS_ANDROID_4_0_0], [test $android_headers_major -ge 4 -a $android_headers_minor -ge 0 ])
 AM_CONDITIONAL([HAS_ANDROID_2_3_0], [test $android_headers_major -ge 2 -a $android_headers_minor -ge 3 ])
 
+AC_ARG_ENABLE(mali-quirks,
+  [  --enable-mali-quirks            Enable Mali GPU driver quirks (default=disabled)],
+  [mali_quirks=$enableval],
+  [mali_quirks="no"])
+AM_CONDITIONAL([WANT_MALI_QUIRKS], [test x"$mali_quirks" = x"yes"])
 
 AC_CONFIG_FILES([
 	Makefile
@@ -217,6 +232,10 @@ AC_CONFIG_FILES([
 	camera/libcamera.pc
 	vibrator/Makefile
 	vibrator/libvibrator.pc
+	media/Makefile
+	media/libmedia.pc
+	wifi/Makefile
+	wifi/libwifi.pc
 	include/Makefile
 	utils/Makefile
 	tests/Makefile
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/hardware/hardware.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/hardware/hardware.c
@@ -18,6 +18,7 @@
 #include <android-config.h>
 #include <dlfcn.h>
 #include <stddef.h>
+#include <errno.h>
 #include <hardware/hardware.h>
 #include <hybris/common/binding.h>
 
@@ -27,15 +28,20 @@ static int (*_hw_get_module)(const char
 
 static int (*_hw_get_module_by_class)(const char *class_id, const char *inst, const struct hw_module_t **module) = NULL;
 
-#define HARDWARE_DLSYM(fptr, sym) do { if (_libhardware == NULL) { _init_lib_hardware(); }; if (*(fptr) == NULL) { *(fptr) = (void *) android_dlsym(_libhardware, sym); } } while (0) 
+#define HARDWARE_DLSYM(fptr, sym) do { if (*(fptr) == NULL) { *(fptr) = (void *) android_dlsym(_libhardware, sym); } } while (0)
 
-static void _init_lib_hardware()
+static void *_init_lib_hardware()
 {
-	_libhardware = (void *) android_dlopen("libhardware.so", RTLD_LAZY);
+	if (!_libhardware)
+		_libhardware = (void *) android_dlopen("libhardware.so", RTLD_LAZY);
+	return _libhardware;
 }
 
 int hw_get_module(const char *id, const struct hw_module_t **module)
 {
+	if (!_init_lib_hardware())
+		return -EINVAL;
+
 	HARDWARE_DLSYM(&_hw_get_module, "hw_get_module");
 	return (*_hw_get_module)(id, module);
 }
@@ -43,6 +49,9 @@ int hw_get_module(const char *id, const
 int hw_get_module_by_class(const char *class_id, const char *inst,
                            const struct hw_module_t **module)
 {
+	if (!_init_lib_hardware())
+		return -EINVAL;
+
 	HARDWARE_DLSYM(&_hw_get_module_by_class, "hw_get_module_by_class");
 	return (*_hw_get_module_by_class)(class_id, inst, module);
 }
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/Makefile.am
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/Makefile.am
@@ -65,6 +65,16 @@ propertiesincludedir = $(includedir)/hyb
 propertiesinclude_HEADERS = \
 	hybris/properties/properties.h
 
+mediaincludedir = $(includedir)/hybris/media
+mediainclude_HEADERS = \
+	hybris/media/media_compatibility_layer.h \
+	hybris/media/media_codec_layer.h \
+	hybris/media/media_codec_list.h \
+	hybris/media/media_format_layer.h \
+	hybris/media/media_recorder_layer.h \
+	hybris/media/surface_texture_client_hybris.h \
+	hybris/media/recorder_compatibility_layer.h
+
 dlfcnincludedir = $(includedir)/hybris/dlfcn
 dlfcninclude_HEADERS = \
 	hybris/dlfcn/dlfcn.h
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/camera/camera_compatibility_layer.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/camera/camera_compatibility_layer.h
@@ -37,6 +37,12 @@ extern "C" {
         FRONT_FACING_CAMERA_TYPE
     } CameraType;
 
+    typedef enum
+    {
+        PREVIEW_CALLBACK_DISABLED,
+        PREVIEW_CALLBACK_ENABLED
+    } PreviewCallbackMode;
+
     struct CameraControl;
 
     typedef void (*on_msg_error)(void* context);
@@ -47,6 +53,7 @@ extern "C" {
     typedef void (*on_data_raw_image)(void* data, uint32_t data_size, void* context);
     typedef void (*on_data_compressed_image)(void* data, uint32_t data_size, void* context);
     typedef void (*on_preview_texture_needs_update)(void* context);
+    typedef void (*on_preview_frame)(void* data, uint32_t data_size, void* context);
 
     struct CameraControlListener
     {
@@ -73,10 +80,14 @@ extern "C" {
         on_preview_texture_needs_update on_preview_texture_needs_update_cb;
 
         void* context;
+
+        // Called when there is a new preview frame
+        on_preview_frame on_preview_frame_cb;
     };
 
     // Initializes a connection to the camera, returns NULL on error.
     struct CameraControl* android_camera_connect_to(CameraType camera_type, struct CameraControlListener* listener);
+    struct CameraControl* android_camera_connect_by_id(int32_t camera_id, struct CameraControlListener* listener);
 
     // Disconnects the camera and deletes the pointer
     void android_camera_disconnect(struct CameraControl* control);
@@ -135,6 +146,9 @@ extern "C" {
     // completed. Ideally, this is done from the raw data callback.
     void android_camera_take_snapshot(struct CameraControl* control);
 
+    // Enable or disable the preview callback for clients that want software frames
+    int android_camera_set_preview_callback_mode(struct CameraControl* control, PreviewCallbackMode mode);
+
 #ifdef __cplusplus
 }
 #endif
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/camera/camera_compatibility_layer_capabilities.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/camera/camera_compatibility_layer_capabilities.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Canonical Ltd
+ * Copyright (C) 2013-2014 Canonical Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -30,7 +30,8 @@ extern "C" {
         FLASH_MODE_OFF,
         FLASH_MODE_AUTO,
         FLASH_MODE_ON,
-        FLASH_MODE_TORCH
+        FLASH_MODE_TORCH,
+        FLASH_MODE_RED_EYE
     } FlashMode;
 
     typedef enum
@@ -48,7 +49,8 @@ extern "C" {
         SCENE_MODE_ACTION,
         SCENE_MODE_NIGHT,
         SCENE_MODE_PARTY,
-        SCENE_MODE_SUNSET
+        SCENE_MODE_SUNSET,
+        SCENE_MODE_HDR
     } SceneMode;
 
     typedef enum
@@ -92,28 +94,36 @@ extern "C" {
         int bottom;
         int right;
         int weight;
-    } FocusRegion;
+    } FocusRegion, MeteringRegion;
 
     typedef void (*size_callback)(void* ctx, int width, int height);
+    typedef void (*scene_mode_callback)(void* ctx, SceneMode mode);
+    typedef void (*flash_mode_callback)(void* ctx, FlashMode mode);
 
     // Dumps the camera parameters to stdout.
     void android_camera_dump_parameters(struct CameraControl* control);
 
     // Query camera parameters
     int android_camera_get_number_of_devices();
+    int android_camera_get_device_info(int32_t camera_id, int* facing, int* orientation);
     void android_camera_enumerate_supported_preview_sizes(struct CameraControl* control, size_callback cb, void* ctx);
     void android_camera_get_preview_fps_range(struct CameraControl* control, int* min, int* max);
     void android_camera_get_preview_fps(struct CameraControl* control, int* fps);
     void android_camera_enumerate_supported_picture_sizes(struct CameraControl* control, size_callback cb, void* ctx);
+    void android_camera_enumerate_supported_thumbnail_sizes(struct CameraControl* control, size_callback cb, void* ctx);
     void android_camera_get_preview_size(struct CameraControl* control, int* width, int* height);
     void android_camera_get_picture_size(struct CameraControl* control, int* width, int* height);
+    void android_camera_get_thumbnail_size(struct CameraControl* control, int* width, int* height);
+    void android_camera_get_jpeg_quality(struct CameraControl* control, int* quality);
 
     void android_camera_get_current_zoom(struct CameraControl* control, int* zoom);
     void android_camera_get_max_zoom(struct CameraControl* control, int* max_zoom);
 
     void android_camera_get_effect_mode(struct CameraControl* control, EffectMode* mode);
     void android_camera_get_flash_mode(struct CameraControl* control, FlashMode* mode);
+    void android_camera_enumerate_supported_flash_modes(struct CameraControl* control, flash_mode_callback cb, void* ctx);
     void android_camera_get_white_balance_mode(struct CameraControl* control, WhiteBalanceMode* mode);
+    void android_camera_enumerate_supported_scene_modes(struct CameraControl* control, scene_mode_callback cb, void* ctx);
     void android_camera_get_scene_mode(struct CameraControl* control, SceneMode* mode);
     void android_camera_get_auto_focus_mode(struct CameraControl* control, AutoFocusMode* mode);
     void android_camera_get_preview_format(struct CameraControl* control, CameraPixelFormat* format);
@@ -122,18 +132,24 @@ extern "C" {
     void android_camera_set_preview_size(struct CameraControl* control, int width, int height);
     void android_camera_set_preview_fps(struct CameraControl* control, int fps);
     void android_camera_set_picture_size(struct CameraControl* control, int width, int height);
+    void android_camera_set_thumbnail_size(struct CameraControl* control, int width, int height);
     void android_camera_set_effect_mode(struct CameraControl* control, EffectMode mode);
     void android_camera_set_flash_mode(struct CameraControl* control, FlashMode mode);
     void android_camera_set_white_balance_mode(struct CameraControl* control, WhiteBalanceMode mode);
     void android_camera_set_scene_mode(struct CameraControl* control, SceneMode mode);
     void android_camera_set_auto_focus_mode(struct CameraControl* control, AutoFocusMode mode);
     void android_camera_set_preview_format(struct CameraControl* control, CameraPixelFormat format);
+    void android_camera_set_jpeg_quality(struct CameraControl* control, int quality);
 
     void android_camera_set_focus_region(struct CameraControl* control, FocusRegion* region);
     void android_camera_reset_focus_region(struct CameraControl* control);
 
+    void android_camera_set_metering_region(struct CameraControl* control, MeteringRegion* region);
+    void android_camera_reset_metering_region(struct CameraControl* control);
+
     // Set photo metadata
     void android_camera_set_rotation(struct CameraControl* control, int rotation);
+    void android_camera_set_location(struct CameraControl* control, const float* latitude, const float* longitude, const float* altitude, int timestamp, const char* method);
 
     // Video support
     void android_camera_enumerate_supported_video_sizes(struct CameraControl* control, size_callback cb, void* ctx);
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/camera/camera_compatibility_layer_configuration_translator.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/camera/camera_compatibility_layer_configuration_translator.h
@@ -96,6 +96,7 @@ extern "C" {
         m.add(android::String8(android::CameraParameters::FLASH_MODE_AUTO), FLASH_MODE_AUTO);
         m.add(android::String8(android::CameraParameters::FLASH_MODE_ON), FLASH_MODE_ON);
         m.add(android::String8(android::CameraParameters::FLASH_MODE_TORCH), FLASH_MODE_TORCH);
+        m.add(android::String8(android::CameraParameters::FLASH_MODE_RED_EYE), FLASH_MODE_RED_EYE);
 
         return m;
     }
@@ -108,22 +109,24 @@ extern "C" {
         android::CameraParameters::SCENE_MODE_ACTION,
         android::CameraParameters::SCENE_MODE_NIGHT,
         android::CameraParameters::SCENE_MODE_PARTY,
-        android::CameraParameters::SCENE_MODE_SUNSET
+        android::CameraParameters::SCENE_MODE_SUNSET,
+        android::CameraParameters::SCENE_MODE_HDR
     };
 
-    static android::KeyedVector<android::String8, SceneMode> init_scene_modes_lut()
+    static android::DefaultKeyedVector<android::String8, SceneMode> init_scene_modes_lut()
     {
-        android::KeyedVector<android::String8, SceneMode> m;
+        android::DefaultKeyedVector<android::String8, SceneMode> m(SCENE_MODE_AUTO);
         m.add(android::String8(android::CameraParameters::SCENE_MODE_AUTO), SCENE_MODE_AUTO);
         m.add(android::String8(android::CameraParameters::SCENE_MODE_ACTION), SCENE_MODE_ACTION);
         m.add(android::String8(android::CameraParameters::SCENE_MODE_NIGHT), SCENE_MODE_NIGHT);
         m.add(android::String8(android::CameraParameters::SCENE_MODE_PARTY), SCENE_MODE_PARTY);
         m.add(android::String8(android::CameraParameters::SCENE_MODE_SUNSET), SCENE_MODE_SUNSET);
+        m.add(android::String8(android::CameraParameters::SCENE_MODE_HDR), SCENE_MODE_HDR);
 
         return m;
     }
 
-    static android::KeyedVector<android::String8, SceneMode> scene_modes_lut = init_scene_modes_lut();
+    static android::DefaultKeyedVector<android::String8, SceneMode> scene_modes_lut = init_scene_modes_lut();
 
     static const char* auto_focus_modes[] =
     {
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/common/binding.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/common/binding.h
@@ -32,7 +32,6 @@ const char *android_dlerror(void);
 int android_dladdr(const void *addr, void *info);
 
 
-
 /**
  *         XXX AUTO-GENERATED FILE XXX
  *
@@ -41,7 +40,7 @@ int android_dladdr(const void *addr, voi
  * an updated version of this header file:
  *
  *    python utils/generate_wrapper_macros.py > \
- *       hybris/include/hybris/common/binding.h
+ *       hybris/include/hybris/internal/binding.h
  *
  * If you need macros with more arguments, just customize the
  * MAX_ARGS variable in generate_wrapper_macros.py.
@@ -65,6 +64,12 @@ int android_dladdr(const void *addr, voi
         name##_handle = android_dlopen(path, RTLD_LAZY); \
     }
 
+#define HYBRIS_LIRBARY_CHECK_SYMBOL(name) \
+    bool hybris_##name##_check_for_symbol(const char *sym) \
+    { \
+        return android_dlsym(name##_handle, sym) != NULL; \
+    }
+
 
 
 #define HYBRIS_IMPLEMENT_FUNCTION0(name, return_type, symbol) \
@@ -435,7 +440,7 @@ int android_dladdr(const void *addr, voi
  * an updated version of this header file:
  *
  *    python utils/generate_wrapper_macros.py > \
- *       hybris/include/hybris/common/binding.h
+ *       hybris/include/hybris/internal/binding.h
  *
  * If you need macros with more arguments, just customize the
  * MAX_ARGS variable in generate_wrapper_macros.py.
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/input/input_stack_compatibility_layer.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/input/input_stack_compatibility_layer.h
@@ -109,6 +109,7 @@ extern "C" {
         int input_area_height;
     };
 
+    int android_input_check_availability();
     void android_input_stack_initialize(
         struct AndroidEventListener* listener,
         struct InputStackConfiguration* input_stack_configuration);
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/internal/camera_control.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/internal/camera_control.h
@@ -19,7 +19,11 @@
 
 #include <camera/Camera.h>
 #include <camera/CameraParameters.h>
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
 #include <gui/SurfaceTexture.h>
+#else
+#include <gui/GLConsumer.h>
+#endif
 
 #include <stdint.h>
 #include <unistd.h>
@@ -31,16 +35,27 @@ extern "C" {
 struct CameraControlListener;
 
 struct CameraControl : public android::CameraListener,
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
     public android::SurfaceTexture::FrameAvailableListener
+#else
+    public android::GLConsumer::FrameAvailableListener
+#endif
 {
     android::Mutex guard;
     CameraControlListener* listener;
     android::sp<android::Camera> camera;
     android::CameraParameters camera_parameters;
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2
     android::sp<android::SurfaceTexture> preview_texture;
-
-    // From android::SurfaceTexture::FrameAvailableListener
+#else
+    android::sp<android::GLConsumer> preview_texture;
+#endif
+    // From android::SurfaceTexture/GLConsumer::FrameAvailableListener
+#if ANDROID_VERSION_MAJOR==5 && ANDROID_VERSION_MINOR>=1
+    void onFrameAvailable(const android::BufferItem& item);
+#else
     void onFrameAvailable();
+#endif
 
     // From android::CameraListener
     void notify(int32_t msg_type, int32_t ext1, int32_t ext2);
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/internal/surface_flinger_compatibility_layer_internal.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/internal/surface_flinger_compatibility_layer_internal.h
@@ -25,6 +25,7 @@
 
 #include <utils/misc.h>
 
+#include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 #include <ui/PixelFormat.h>
 #include <ui/Region.h>
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/decoding_service.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef DECODING_SERVICE_H_
+#define DECODING_SERVICE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <unistd.h>
+
+// TODO: This file is empty for now but will have the decoding_service_* functions
+// from media_codec_layer.cpp after it's figured out why these functions crash when located
+// in decoding_service.cpp
+
+//void decoding_service_init();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/media_codec_layer.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef MEDIA_CODEC_LAYER_H_
+#define MEDIA_CODEC_LAYER_H_
+
+#include <stdint.h>
+#include <unistd.h>
+
+#ifdef SIMPLE_PLAYER
+#include <media/stagefright/MediaCodec.h>
+#endif
+
+#include <hybris/media/media_format_layer.h>
+#include <hybris/media/surface_texture_client_hybris.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    typedef void* MediaCodecDelegate;
+    typedef void* DSSessionWrapperHybris;
+
+    typedef void (*on_texture_needs_update)(void *context);
+    void media_codec_set_texture_needs_update_cb(MediaCodecDelegate delegate, on_texture_needs_update cb, void *context);
+
+    // DecodingService API
+    void decoding_service_init();
+
+    IGBCWrapperHybris decoding_service_get_igraphicbufferconsumer();
+    IGBPWrapperHybris decoding_service_get_igraphicbufferproducer();
+    DSSessionWrapperHybris decoding_service_create_session(uint32_t handle);
+    void decoding_service_set_client_death_cb(DecodingClientDeathCbHybris cb, uint32_t handle, void *context);
+
+    MediaCodecDelegate media_codec_create_by_codec_name(const char *name);
+    MediaCodecDelegate media_codec_create_by_codec_type(const char *type);
+
+#ifdef SIMPLE_PLAYER
+    android::MediaCodec* media_codec_get(MediaCodecDelegate delegate);
+#endif
+
+    void media_codec_delegate_destroy(MediaCodecDelegate delegate);
+    void media_codec_delegate_ref(MediaCodecDelegate delegate);
+    void media_codec_delegate_unref(MediaCodecDelegate delegate);
+
+#ifdef SIMPLE_PLAYER
+    int media_codec_configure(MediaCodecDelegate delegate, MediaFormat format, void *nativeWindow, uint32_t flags);
+#else
+    int media_codec_configure(MediaCodecDelegate delegate, MediaFormat format, SurfaceTextureClientHybris stc, uint32_t flags);
+#endif
+    int media_codec_set_surface_texture_client(MediaCodecDelegate delegate, SurfaceTextureClientHybris stc);
+
+    int media_codec_queue_csd(MediaCodecDelegate delegate, MediaFormat format);
+    int media_codec_start(MediaCodecDelegate delegate);
+    int media_codec_stop(MediaCodecDelegate delegate);
+    int media_codec_release(MediaCodecDelegate delegate);
+    int media_codec_flush(MediaCodecDelegate delegate);
+    size_t media_codec_get_input_buffers_size(MediaCodecDelegate delegate);
+    uint8_t *media_codec_get_nth_input_buffer(MediaCodecDelegate delegate, size_t n);
+    size_t media_codec_get_nth_input_buffer_capacity(MediaCodecDelegate delegate, size_t n);
+    size_t media_codec_get_output_buffers_size(MediaCodecDelegate delegate);
+    uint8_t *media_codec_get_nth_output_buffer(MediaCodecDelegate delegate, size_t n);
+    size_t media_codec_get_nth_output_buffer_capacity(MediaCodecDelegate delegate, size_t n);
+
+    struct _MediaCodecBufferInfo
+    {
+        size_t index;
+        size_t offset;
+        size_t size;
+        int64_t presentation_time_us;
+        uint32_t flags;
+        uint8_t render_retries;
+    };
+    typedef struct _MediaCodecBufferInfo MediaCodecBufferInfo;
+
+    int media_codec_dequeue_output_buffer(MediaCodecDelegate delegate, MediaCodecBufferInfo *info, int64_t timeout_us);
+    int media_codec_queue_input_buffer(MediaCodecDelegate delegate, const MediaCodecBufferInfo *info);
+    int media_codec_dequeue_input_buffer(MediaCodecDelegate delegate, size_t *index, int64_t timeout_us);
+    int media_codec_release_output_buffer(MediaCodecDelegate delegate, size_t index, uint8_t render);
+
+    MediaFormat media_codec_get_output_format(MediaCodecDelegate delegate);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MEDIA_CODEC_LAYER_H_
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/media_codec_list.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef MEDIA_CODEC_LIST_PRIV_H_
+#define MEDIA_CODEC_LIST_PRIV_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    ssize_t media_codec_list_find_codec_by_type(const char *type, bool encoder, size_t startIndex);
+    ssize_t media_codec_list_find_codec_by_name(const char *name);
+    size_t media_codec_list_count_codecs();
+    void media_codec_list_get_codec_info_at_id(size_t index);
+    const char *media_codec_list_get_codec_name(size_t index);
+    bool media_codec_list_is_encoder(size_t index);
+    size_t media_codec_list_get_num_supported_types(size_t index);
+    size_t media_codec_list_get_nth_supported_type_len(size_t index, size_t n);
+    int media_codec_list_get_nth_supported_type(size_t index, char *type, size_t n);
+
+    struct _profile_level
+    {
+        uint32_t profile;
+        uint32_t level;
+    };
+    typedef struct _profile_level profile_level;
+
+    size_t media_codec_list_get_num_profile_levels(size_t index, const char*);
+    size_t media_codec_list_get_num_color_formats(size_t index, const char*);
+    int media_codec_list_get_nth_codec_profile_level(size_t index, const char *type, profile_level *pro_level, size_t n);
+    int media_codec_list_get_codec_color_formats(size_t index, const char *type, uint32_t *color_formats);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MEDIA_CODEC_LIST_PRIV_H_
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/media_compatibility_layer.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef MEDIA_COMPATIBILITY_LAYER_H_
+#define MEDIA_COMPATIBILITY_LAYER_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include <GLES2/gl2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    // Common compat calls
+    int media_compat_check_availability();
+
+    // Callback types
+    typedef void (*on_msg_set_video_size)(int height, int width, void *context);
+    typedef void (*on_video_texture_needs_update)(void *context);
+    typedef void (*on_msg_error)(void *context);
+    typedef void (*on_playback_complete)(void *context);
+    typedef void (*on_media_prepared)(void *context);
+
+    struct MediaPlayerWrapper;
+
+    // ----- Start of C API ----- //
+
+    // Callback setters
+    void android_media_set_video_size_cb(struct MediaPlayerWrapper *mp, on_msg_set_video_size cb, void *context);
+    void android_media_set_video_texture_needs_update_cb(struct MediaPlayerWrapper *mp, on_video_texture_needs_update cb, void *context);
+    void android_media_set_error_cb(struct MediaPlayerWrapper *mp, on_msg_error cb, void *context);
+    void android_media_set_playback_complete_cb(struct MediaPlayerWrapper *mp, on_playback_complete cb, void *context);
+    void android_media_set_media_prepared_cb(struct MediaPlayerWrapper *mp, on_media_prepared cb, void *context);
+
+    // Main player control API
+    struct MediaPlayerWrapper *android_media_new_player();
+    int android_media_set_data_source(struct MediaPlayerWrapper *mp, const char* url);
+    int android_media_set_preview_texture(struct MediaPlayerWrapper *mp, int texture_id);
+    void android_media_update_surface_texture(struct MediaPlayerWrapper *mp);
+    void android_media_surface_texture_get_transformation_matrix(struct MediaPlayerWrapper *mp, GLfloat*matrix);
+    int android_media_play(struct MediaPlayerWrapper *mp);
+    int android_media_pause(struct MediaPlayerWrapper *mp);
+    int android_media_stop(struct MediaPlayerWrapper *mp);
+    bool android_media_is_playing(struct MediaPlayerWrapper *mp);
+
+    int android_media_seek_to(struct MediaPlayerWrapper *mp, int msec);
+    int android_media_get_current_position(struct MediaPlayerWrapper *mp, int *msec);
+    int android_media_get_duration(struct MediaPlayerWrapper *mp, int *msec);
+
+    int android_media_get_volume(struct MediaPlayerWrapper *mp, int *volume);
+    int android_media_set_volume(struct MediaPlayerWrapper *mp, int volume);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MEDIA_COMPATIBILITY_LAYER_H_
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/media_format_layer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef MEDIA_FORMAT_LAYER_H_
+#define MEDIA_FORMAT_LAYER_H_
+
+#include <stddef.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    typedef void* MediaFormat;
+
+    MediaFormat media_format_create_video_format(const char *mime, int32_t width, int32_t height, int64_t duration_us, int32_t max_input_size);
+
+    void media_format_destroy(MediaFormat format);
+    void media_format_ref(MediaFormat format);
+    void media_format_unref(MediaFormat format);
+
+    void media_format_set_byte_buffer(MediaFormat format, const char *key, uint8_t *data, size_t size);
+
+    const char* media_format_get_mime(MediaFormat format);
+    int64_t media_format_get_duration_us(MediaFormat format);
+    int32_t media_format_get_width(MediaFormat format);
+    int32_t media_format_get_height(MediaFormat format);
+    int32_t media_format_get_max_input_size(MediaFormat format);
+    int32_t media_format_get_stride(MediaFormat format);
+    int32_t media_format_get_slice_height(MediaFormat format);
+    int32_t media_format_get_color_format(MediaFormat format);
+    int32_t media_format_get_crop_left(MediaFormat format);
+    int32_t media_format_get_crop_right(MediaFormat format);
+    int32_t media_format_get_crop_top(MediaFormat format);
+    int32_t media_format_get_crop_bottom(MediaFormat format);
+
+    // TODO: Add getter for CSD buffer
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MEDIA_FORMAT_LAYER_H_
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/media_recorder_layer.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2013-2014 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 MEDIA_RECORDER_LAYER_H_
+#define MEDIA_RECORDER_LAYER_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    // Media Recorder Observer API
+    struct MediaRecorderObserver;
+    struct MediaRecorderObserver *android_media_recorder_observer_new();
+
+    typedef void (*media_recording_started_cb)(bool started, void *context);
+    void android_media_recorder_observer_set_cb(struct MediaRecorderObserver *observer, media_recording_started_cb cb, void *context);
+
+    struct MediaRecorderWrapper;
+    struct CameraControl;
+
+    // Values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_VIDEO_SOURCE_DEFAULT = 0,
+        ANDROID_VIDEO_SOURCE_CAMERA = 1,
+        ANDROID_VIDEO_SOURCE_GRALLOC_BUFFER = 2
+    } VideoSource;
+
+    // Values are from andoid /system/core/include/system/audio.h
+    typedef enum
+    {
+        ANDROID_AUDIO_SOURCE_DEFAULT             = 0,
+        ANDROID_AUDIO_SOURCE_MIC                 = 1,
+        ANDROID_AUDIO_SOURCE_VOICE_UPLINK        = 2,
+        ANDROID_AUDIO_SOURCE_VOICE_DOWNLINK      = 3,
+        ANDROID_AUDIO_SOURCE_VOICE_CALL          = 4,
+        ANDROID_AUDIO_SOURCE_CAMCORDER           = 5,
+        ANDROID_AUDIO_SOURCE_VOICE_RECOGNITION   = 6,
+        ANDROID_AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
+        ANDROID_AUDIO_SOURCE_REMOTE_SUBMIX       = 8,
+        ANDROID_AUDIO_SOURCE_CNT,
+        ANDROID_AUDIO_SOURCE_MAX                 = ANDROID_AUDIO_SOURCE_CNT - 1
+    } AudioSource;
+
+    // Values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_OUTPUT_FORMAT_DEFAULT = 0,
+        ANDROID_OUTPUT_FORMAT_THREE_GPP = 1,
+        ANDROID_OUTPUT_FORMAT_MPEG_4 = 2,
+        ANDROID_OUTPUT_FORMAT_AUDIO_ONLY_START = 3,
+        /* These are audio only file formats */
+        ANDROID_OUTPUT_FORMAT_RAW_AMR = 3, // to be backward compatible
+        ANDROID_OUTPUT_FORMAT_AMR_NB = 3,
+        ANDROID_OUTPUT_FORMAT_AMR_WB = 4,
+        ANDROID_OUTPUT_FORMAT_AAC_ADIF = 5,
+        ANDROID_OUTPUT_FORMAT_AAC_ADTS = 6,
+        /* Stream over a socket, limited to a single stream */
+        ANDROID_OUTPUT_FORMAT_RTP_AVP = 7,
+        /* H.264/AAC data encapsulated in MPEG2/TS */
+        ANDROID_OUTPUT_FORMAT_MPEG2TS = 8
+    } OutputFormat;
+
+    // Values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_VIDEO_ENCODER_DEFAULT = 0,
+        ANDROID_VIDEO_ENCODER_H263 = 1,
+        ANDROID_VIDEO_ENCODER_H264 = 2,
+        ANDROID_VIDEO_ENCODER_MPEG_4_SP = 3
+    } VideoEncoder;
+
+    // Values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_AUDIO_ENCODER_DEFAULT = 0,
+        ANDROID_AUDIO_ENCODER_AMR_NB = 1,
+        ANDROID_AUDIO_ENCODER_AMR_WB = 2,
+        ANDROID_AUDIO_ENCODER_AAC = 3,
+        ANDROID_AUDIO_ENCODER_HE_AAC = 4,
+        ANDROID_AUDIO_ENCODER_AAC_ELD = 5
+    } AudioEncoder;
+
+    /* Defines how many bytes to read of the microphone at a time. This value
+       is how many bytes AudioFlinger would read max at a time from the microphone,
+       so duplicate using that value here since that code is well tested. */
+    #define MIC_READ_BUF_SIZE 960
+
+    // Callback types
+    typedef void (*on_recorder_msg_error)(void *context);
+    typedef void (*on_recorder_read_audio)(void *context);
+
+    // Callback setters
+    void android_recorder_set_error_cb(struct MediaRecorderWrapper *mr, on_recorder_msg_error cb,
+                                       void *context);
+    void android_recorder_set_audio_read_cb(struct MediaRecorderWrapper *mr, on_recorder_read_audio cb,
+                                       void *context);
+
+    // Main recorder control API
+    struct MediaRecorderWrapper *android_media_new_recorder();
+    int android_recorder_initCheck(struct MediaRecorderWrapper *mr);
+    int android_recorder_setCamera(struct MediaRecorderWrapper *mr, struct CameraControl* control);
+    int android_recorder_setVideoSource(struct MediaRecorderWrapper *mr, VideoSource vs);
+    int android_recorder_setAudioSource(struct MediaRecorderWrapper *mr, AudioSource as);
+    int android_recorder_setOutputFormat(struct MediaRecorderWrapper *mr, OutputFormat of);
+    int android_recorder_setVideoEncoder(struct MediaRecorderWrapper *mr, VideoEncoder ve);
+    int android_recorder_setAudioEncoder(struct MediaRecorderWrapper *mr, AudioEncoder ae);
+    int android_recorder_setOutputFile(struct MediaRecorderWrapper *mr, int fd);
+    int android_recorder_setVideoSize(struct MediaRecorderWrapper *mr, int width, int height);
+    int android_recorder_setVideoFrameRate(struct MediaRecorderWrapper *mr, int frames_per_second);
+    int android_recorder_setParameters(struct MediaRecorderWrapper *mr, const char* parameters);
+    int android_recorder_start(struct MediaRecorderWrapper *mr);
+    int android_recorder_stop(struct MediaRecorderWrapper *mr);
+    int android_recorder_prepare(struct MediaRecorderWrapper *mr);
+    int android_recorder_reset(struct MediaRecorderWrapper *mr);
+    int android_recorder_close(struct MediaRecorderWrapper *mr);
+    int android_recorder_release(struct MediaRecorderWrapper *mr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/recorder_compatibility_layer.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 RECORDER_COMPATIBILITY_LAYER_H_
+#define RECORDER_COMPATIBILITY_LAYER_H_
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    struct MediaRecorderWrapper;
+    struct CameraControl;
+
+    // values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_VIDEO_SOURCE_DEFAULT = 0,
+        ANDROID_VIDEO_SOURCE_CAMERA = 1,
+        ANDROID_VIDEO_SOURCE_GRALLOC_BUFFER = 2
+    } VideoSource;
+
+    // values are from andoid /system/core/include/system/audio.h
+    typedef enum
+    {
+        ANDROID_AUDIO_SOURCE_DEFAULT             = 0,
+        ANDROID_AUDIO_SOURCE_MIC                 = 1,
+        ANDROID_AUDIO_SOURCE_VOICE_UPLINK        = 2,
+        ANDROID_AUDIO_SOURCE_VOICE_DOWNLINK      = 3,
+        ANDROID_AUDIO_SOURCE_VOICE_CALL          = 4,
+        ANDROID_AUDIO_SOURCE_CAMCORDER           = 5,
+        ANDROID_AUDIO_SOURCE_VOICE_RECOGNITION   = 6,
+        ANDROID_AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
+        ANDROID_AUDIO_SOURCE_REMOTE_SUBMIX       = 8,
+        ANDROID_AUDIO_SOURCE_CNT,
+        ANDROID_AUDIO_SOURCE_MAX                 = ANDROID_AUDIO_SOURCE_CNT - 1
+    } AudioSource;
+
+    // values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_OUTPUT_FORMAT_DEFAULT = 0,
+        ANDROID_OUTPUT_FORMAT_THREE_GPP = 1,
+        ANDROID_OUTPUT_FORMAT_MPEG_4 = 2,
+        ANDROID_OUTPUT_FORMAT_AUDIO_ONLY_START = 3,
+        /* These are audio only file formats */
+        ANDROID_OUTPUT_FORMAT_RAW_AMR = 3, //to be backward compatible
+        ANDROID_OUTPUT_FORMAT_AMR_NB = 3,
+        ANDROID_OUTPUT_FORMAT_AMR_WB = 4,
+        ANDROID_OUTPUT_FORMAT_AAC_ADIF = 5,
+        ANDROID_OUTPUT_FORMAT_AAC_ADTS = 6,
+        /* Stream over a socket, limited to a single stream */
+        ANDROID_OUTPUT_FORMAT_RTP_AVP = 7,
+        /* H.264/AAC data encapsulated in MPEG2/TS */
+        ANDROID_OUTPUT_FORMAT_MPEG2TS = 8
+    } OutputFormat;
+
+    // values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_VIDEO_ENCODER_DEFAULT = 0,
+        ANDROID_VIDEO_ENCODER_H263 = 1,
+        ANDROID_VIDEO_ENCODER_H264 = 2,
+        ANDROID_VIDEO_ENCODER_MPEG_4_SP = 3
+    } VideoEncoder;
+
+    // values are from andoid /frameworks/av/include/media/mediarecorder.h
+    typedef enum
+    {
+        ANDROID_AUDIO_ENCODER_DEFAULT = 0,
+        ANDROID_AUDIO_ENCODER_AMR_NB = 1,
+        ANDROID_AUDIO_ENCODER_AMR_WB = 2,
+        ANDROID_AUDIO_ENCODER_AAC = 3,
+        ANDROID_AUDIO_ENCODER_HE_AAC = 4,
+        ANDROID_AUDIO_ENCODER_AAC_ELD = 5
+    } AudioEncoder;
+
+    // Callback types
+    typedef void (*on_recorder_msg_error)(void *context);
+
+    // Callback setters
+    void android_recorder_set_error_cb(struct MediaRecorderWrapper *mr, on_recorder_msg_error cb,
+                                       void *context);
+
+    // Main recorder control API
+    struct MediaRecorderWrapper *android_media_new_recorder();
+    int android_recorder_initCheck(struct MediaRecorderWrapper *mr);
+    int android_recorder_setCamera(struct MediaRecorderWrapper *mr, struct CameraControl* control);
+    int android_recorder_setVideoSource(struct MediaRecorderWrapper *mr, VideoSource vs);
+    int android_recorder_setAudioSource(struct MediaRecorderWrapper *mr, AudioSource as);
+    int android_recorder_setOutputFormat(struct MediaRecorderWrapper *mr, OutputFormat of);
+    int android_recorder_setVideoEncoder(struct MediaRecorderWrapper *mr, VideoEncoder ve);
+    int android_recorder_setAudioEncoder(struct MediaRecorderWrapper *mr, AudioEncoder ae);
+    int android_recorder_setOutputFile(struct MediaRecorderWrapper *mr, int fd);
+    int android_recorder_setVideoSize(struct MediaRecorderWrapper *mr, int width, int height);
+    int android_recorder_setVideoFrameRate(struct MediaRecorderWrapper *mr, int frames_per_second);
+    int android_recorder_setParameters(struct MediaRecorderWrapper *mr, const char* parameters);
+    int android_recorder_start(struct MediaRecorderWrapper *mr);
+    int android_recorder_stop(struct MediaRecorderWrapper *mr);
+    int android_recorder_prepare(struct MediaRecorderWrapper *mr);
+    int android_recorder_reset(struct MediaRecorderWrapper *mr);
+    int android_recorder_close(struct MediaRecorderWrapper *mr);
+    int android_recorder_release(struct MediaRecorderWrapper *mr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/media/surface_texture_client_hybris.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ */
+
+#ifndef SURFACE_TEXTURE_CLIENT_HYBRIS_H_
+#define SURFACE_TEXTURE_CLIENT_HYBRIS_H_
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <EGL/egl.h>
+
+#ifdef __ARM_PCS_VFP
+#define FP_ATTRIB __attribute__((pcs("aapcs")))
+#else
+#define FP_ATTRIB
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    // Taken from native_window.h
+    enum {
+        WINDOW_FORMAT_RGBA_8888     = 1,
+        WINDOW_FORMAT_RGBX_8888     = 2,
+        WINDOW_FORMAT_RGB_565       = 4,
+    };
+
+    typedef void* SurfaceTextureClientHybris;
+    typedef void* GLConsumerHybris;
+    typedef void* GLConsumerWrapperHybris;
+    typedef void* IGraphicBufferConsumerHybris;
+    typedef void* IGraphicBufferProducerHybris;
+    typedef void* IGBCWrapperHybris;
+    typedef void* IGBPWrapperHybris;
+
+    /** Used to set a callback function to be called when a frame is ready to be rendered **/
+    typedef void (*FrameAvailableCbHybris)(GLConsumerWrapperHybris wrapper, void *context);
+    typedef void (*DecodingClientDeathCbHybris)(void *context);
+
+    //SurfaceTextureClientHybris surface_texture_client_get_instance();
+    SurfaceTextureClientHybris surface_texture_client_create(EGLNativeWindowType native_window);
+    SurfaceTextureClientHybris surface_texture_client_create_by_id(unsigned int texture_id);
+    SurfaceTextureClientHybris surface_texture_client_create_by_igbp(IGBPWrapperHybris wrapper);
+    GLConsumerWrapperHybris gl_consumer_create_by_id_with_igbc(unsigned int texture_id, IGBCWrapperHybris wrapper);
+    int gl_consumer_set_frame_available_cb(GLConsumerWrapperHybris wrapper, FrameAvailableCbHybris cb, void *context);
+    void gl_consumer_get_transformation_matrix(GLConsumerWrapperHybris wrapper, float *matrix) FP_ATTRIB;
+    void gl_consumer_update_texture(GLConsumerWrapperHybris wrapper);
+    uint8_t surface_texture_client_is_ready_for_rendering(SurfaceTextureClientHybris stc);
+    uint8_t surface_texture_client_hardware_rendering(SurfaceTextureClientHybris stc);
+    void surface_texture_client_set_hardware_rendering(SurfaceTextureClientHybris stc, uint8_t hardware_rendering);
+    void surface_texture_client_get_transformation_matrix(SurfaceTextureClientHybris stc, float *matrix) FP_ATTRIB;
+    void surface_texture_client_update_texture(SurfaceTextureClientHybris stc);
+    void surface_texture_client_destroy(SurfaceTextureClientHybris stc);
+    void surface_texture_client_ref(SurfaceTextureClientHybris stc);
+    void surface_texture_client_unref(SurfaceTextureClientHybris stc);
+    void surface_texture_client_set_surface_texture(SurfaceTextureClientHybris stc, EGLNativeWindowType native_window);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SURFACE_TEXTURE_CLIENT_HYBRIS_H_
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/include/hybris/ui/ui_compatibility_layer.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/include/hybris/ui/ui_compatibility_layer.h
@@ -50,8 +50,10 @@ extern "C" {
 
     void* graphic_buffer_get_native_buffer(struct graphic_buffer *buffer);
 
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
     void graphic_buffer_set_index(struct graphic_buffer *buffer, int index);
     int graphic_buffer_get_index(struct graphic_buffer *buffer);
+#endif
 
     int graphic_buffer_init_check(struct graphic_buffer *buffer);
 
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/input/is.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/input/is.c
@@ -28,6 +28,14 @@
 
 HYBRIS_LIBRARY_INITIALIZE(is, COMPAT_LIBRARY_PATH);
 
+int android_input_check_availability()
+{
+	/* Both are defined via HYBRIS_LIBRARY_INITIALIZE */
+	if (!is_handle)
+		hybris_is_initialize();
+	return is_handle ? 1 : 0;
+}
+
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(is, android_input_stack_initialize,
 	struct AndroidEventListener*, struct InputStackConfiguration*);
 HYBRIS_IMPLEMENT_VOID_FUNCTION0(is, android_input_stack_start);
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/media/Makefile.am
@@ -0,0 +1,17 @@
+lib_LTLIBRARIES = \
+	libmedia.la
+
+libmedia_la_SOURCES = media.c
+libmedia_la_CFLAGS = -I$(top_srcdir)/include
+if WANT_TRACE
+libmedia_la_CFLAGS += -DDEBUG
+endif
+if WANT_DEBUG
+libmedia_la_CFLAGS += -ggdb -O0
+endif
+libmedia_la_LDFLAGS = \
+	$(top_builddir)/common/libhybris-common.la \
+	-version-info "1":"0":"0"
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libmedia.pc
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/media/libmedia.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=@libdir@
+includedir=@includedir@
+
+Name: hybris-media
+Description: libhybris media library
+Version: @VERSION@
+Libs: -L${libdir} -lhybris-common -lmedia
+Cflags: -I${includedir}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/media/media.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2013-2014 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#include <hybris/common/binding.h>
+#include <hybris/media/decoding_service.h>
+#include <hybris/media/media_compatibility_layer.h>
+#include <hybris/media/media_codec_layer.h>
+#include <hybris/media/media_codec_list.h>
+#include <hybris/media/media_format_layer.h>
+#include <hybris/media/media_recorder_layer.h>
+#include <hybris/media/surface_texture_client_hybris.h>
+
+#define COMPAT_LIBRARY_PATH "/system/lib/libmedia_compat_layer.so"
+
+#ifdef __ARM_PCS_VFP
+#define FP_ATTRIB __attribute__((pcs("aapcs")))
+#else
+#define FP_ATTRIB
+#endif
+
+HYBRIS_LIBRARY_INITIALIZE(media, COMPAT_LIBRARY_PATH);
+
+int media_compat_check_availability()
+{
+	/* Both are defined via HYBRIS_LIBRARY_INITIALIZE */
+	hybris_media_initialize();
+	return media_handle ? 1 : 0;
+}
+
+HYBRIS_IMPLEMENT_FUNCTION0(media, struct MediaPlayerWrapper*,
+	android_media_new_player);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, android_media_update_surface_texture,
+	struct MediaPlayerWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_media_play,
+	struct MediaPlayerWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_media_pause,
+	struct MediaPlayerWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_media_stop,
+	struct MediaPlayerWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, bool, android_media_is_playing,
+	struct MediaPlayerWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_seek_to,
+	struct MediaPlayerWrapper*, int);
+
+// Setters
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_set_data_source,
+	struct MediaPlayerWrapper*, const char*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_set_preview_texture,
+	struct MediaPlayerWrapper*, int);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_set_volume,
+	struct MediaPlayerWrapper*, int);
+
+// Getters
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, android_media_surface_texture_get_transformation_matrix,
+	struct MediaPlayerWrapper*, float*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_get_current_position,
+	struct MediaPlayerWrapper*, int*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_get_duration,
+	struct MediaPlayerWrapper*, int*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_get_volume,
+	struct MediaPlayerWrapper*, int*);
+
+// Callbacks
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_video_size_cb,
+	struct MediaPlayerWrapper*, on_msg_set_video_size, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_video_texture_needs_update_cb,
+	struct MediaPlayerWrapper*, on_video_texture_needs_update, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_error_cb,
+	struct MediaPlayerWrapper*, on_msg_error, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_playback_complete_cb,
+	struct MediaPlayerWrapper*, on_playback_complete, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_media_prepared_cb,
+	struct MediaPlayerWrapper*, on_media_prepared, void*);
+
+// DecodingService
+HYBRIS_IMPLEMENT_VOID_FUNCTION0(media, decoding_service_init);
+HYBRIS_IMPLEMENT_FUNCTION0(media, IGBCWrapperHybris,
+	decoding_service_get_igraphicbufferconsumer);
+HYBRIS_IMPLEMENT_FUNCTION0(media, IGraphicBufferProducerHybris,
+	decoding_service_get_igraphicbufferproducer);
+HYBRIS_IMPLEMENT_FUNCTION1(media, DSSessionWrapperHybris,
+	decoding_service_create_session, uint32_t);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, decoding_service_set_client_death_cb,
+	DecodingClientDeathCbHybris, uint32_t, void*);
+
+// Media Codecs
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaCodecDelegate,
+	media_codec_create_by_codec_name, const char*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_delegate_destroy,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_delegate_ref,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_delegate_unref,
+	MediaCodecDelegate);
+
+#ifdef SIMPLE_PLAYER
+HYBRIS_IMPLEMENT_FUNCTION4(media, int, media_codec_configure,
+	MediaCodecDelegate, MediaFormat, void*, uint32_t);
+#else
+HYBRIS_IMPLEMENT_FUNCTION4(media, int, media_codec_configure,
+	MediaCodecDelegate, MediaFormat, SurfaceTextureClientHybris, uint32_t);
+#endif
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, media_codec_set_surface_texture_client,
+	MediaCodecDelegate, SurfaceTextureClientHybris);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, media_codec_queue_csd,
+	MediaCodecDelegate, MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_start,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_stop,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_release,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_flush,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_codec_get_input_buffers_size,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_FUNCTION2(media, uint8_t*, media_codec_get_nth_input_buffer,
+	MediaCodecDelegate, size_t);
+HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_get_nth_input_buffer_capacity,
+	MediaCodecDelegate, size_t);
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_codec_get_output_buffers_size,
+	MediaCodecDelegate);
+HYBRIS_IMPLEMENT_FUNCTION2(media, uint8_t*, media_codec_get_nth_output_buffer,
+	MediaCodecDelegate, size_t);
+HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_get_nth_output_buffer_capacity,
+	MediaCodecDelegate, size_t);
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_dequeue_output_buffer,
+	MediaCodecDelegate, MediaCodecBufferInfo*, int64_t);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, media_codec_queue_input_buffer,
+	MediaCodecDelegate, const MediaCodecBufferInfo*);
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_dequeue_input_buffer,
+	MediaCodecDelegate, size_t*, int64_t);
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_release_output_buffer,
+	MediaCodecDelegate, size_t, uint8_t);
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaFormat, media_codec_get_output_format,
+	MediaCodecDelegate);
+
+HYBRIS_IMPLEMENT_FUNCTION3(media, ssize_t, media_codec_list_find_codec_by_type,
+	const char*, bool, size_t);
+HYBRIS_IMPLEMENT_FUNCTION1(media, ssize_t, media_codec_list_find_codec_by_name,
+	const char *);
+HYBRIS_IMPLEMENT_FUNCTION0(media, size_t, media_codec_list_count_codecs);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_list_get_codec_info_at_id,
+	size_t);
+HYBRIS_IMPLEMENT_FUNCTION1(media, const char*, media_codec_list_get_codec_name,
+	size_t);
+HYBRIS_IMPLEMENT_FUNCTION1(media, bool, media_codec_list_is_encoder,
+	size_t);
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_codec_list_get_num_supported_types,
+	size_t);
+HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_list_get_nth_supported_type_len,
+	size_t, size_t);
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_list_get_nth_supported_type,
+	size_t, char *, size_t);
+HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_list_get_num_profile_levels,
+	size_t, const char*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_list_get_num_color_formats,
+	size_t, const char*);
+HYBRIS_IMPLEMENT_FUNCTION4(media, int, media_codec_list_get_nth_codec_profile_level,
+	size_t, const char*, profile_level*, size_t);
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_list_get_codec_color_formats,
+	size_t, const char*, uint32_t*);
+
+HYBRIS_IMPLEMENT_FUNCTION5(media, MediaFormat, media_format_create_video_format,
+	const char*, int32_t, int32_t, int64_t, int32_t);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_format_destroy,
+	MediaFormat);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_format_ref,
+	MediaFormat);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_format_unref,
+	MediaFormat);
+HYBRIS_IMPLEMENT_VOID_FUNCTION4(media, media_format_set_byte_buffer,
+	MediaFormat, const char*, uint8_t*, size_t);
+HYBRIS_IMPLEMENT_FUNCTION1(media, const char*, media_format_get_mime,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int64_t, media_format_get_duration_us,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_width,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_height,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_max_input_size,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_stride,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_slice_height,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_color_format,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_left,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_right,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_top,
+	MediaFormat);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_bottom,
+	MediaFormat);
+
+// SurfaceTextureClientHybris
+HYBRIS_IMPLEMENT_FUNCTION1(media, SurfaceTextureClientHybris,
+	surface_texture_client_create, EGLNativeWindowType);
+HYBRIS_IMPLEMENT_FUNCTION1(media, SurfaceTextureClientHybris,
+	surface_texture_client_create_by_id, unsigned int);
+HYBRIS_IMPLEMENT_FUNCTION1(media, SurfaceTextureClientHybris,
+	surface_texture_client_create_by_igbp, IGBPWrapperHybris);
+HYBRIS_IMPLEMENT_FUNCTION2(media, GLConsumerWrapperHybris,
+	gl_consumer_create_by_id_with_igbc, unsigned int, IGBCWrapperHybris);
+HYBRIS_IMPLEMENT_FUNCTION3(media, int,
+	gl_consumer_set_frame_available_cb, GLConsumerWrapperHybris, FrameAvailableCbHybris, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, gl_consumer_get_transformation_matrix,
+	GLConsumerWrapperHybris, GLfloat*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, gl_consumer_update_texture,
+	GLConsumerWrapperHybris);
+HYBRIS_IMPLEMENT_FUNCTION1(media, uint8_t,
+	surface_texture_client_is_ready_for_rendering, SurfaceTextureClientHybris);
+HYBRIS_IMPLEMENT_FUNCTION1(media, uint8_t,
+	surface_texture_client_hardware_rendering, SurfaceTextureClientHybris);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, surface_texture_client_set_hardware_rendering,
+	SurfaceTextureClientHybris, uint8_t);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, surface_texture_client_get_transformation_matrix,
+	SurfaceTextureClientHybris, GLfloat*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_update_texture,
+	SurfaceTextureClientHybris);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_destroy,
+	SurfaceTextureClientHybris);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_ref,
+	SurfaceTextureClientHybris);
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_unref,
+	SurfaceTextureClientHybris);
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, surface_texture_client_set_surface_texture,
+	SurfaceTextureClientHybris, EGLNativeWindowType);
+
+// Recorder Observer
+HYBRIS_IMPLEMENT_FUNCTION0(media, struct MediaRecorderObserver*,
+	android_media_recorder_observer_new);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_recorder_observer_set_cb,
+	struct MediaRecorderObserver*, media_recording_started_cb, void*);
+
+// Recorder
+HYBRIS_IMPLEMENT_FUNCTION0(media, struct MediaRecorderWrapper*,
+	android_media_new_recorder);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_initCheck,
+	struct MediaRecorderWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setCamera,
+	struct MediaRecorderWrapper*, struct CameraControl*);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setVideoSource,
+	struct MediaRecorderWrapper*, VideoSource);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setAudioSource,
+	struct MediaRecorderWrapper*, AudioSource);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setOutputFormat,
+	struct MediaRecorderWrapper*, OutputFormat);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setVideoEncoder,
+	struct MediaRecorderWrapper*, VideoEncoder);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setAudioEncoder,
+	struct MediaRecorderWrapper*, AudioEncoder);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setOutputFile,
+	struct MediaRecorderWrapper*, int);
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, android_recorder_setVideoSize,
+	struct MediaRecorderWrapper*, int, int);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setVideoFrameRate,
+	struct MediaRecorderWrapper*, int);
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setParameters,
+	struct MediaRecorderWrapper*, const char*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_start,
+	struct MediaRecorderWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_stop,
+	struct MediaRecorderWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_prepare,
+	struct MediaRecorderWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_reset,
+	struct MediaRecorderWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_close,
+	struct MediaRecorderWrapper*);
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_release,
+	struct MediaRecorderWrapper*);
+
+// Recorder Callbacks
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_recorder_set_error_cb,
+	struct MediaRecorderWrapper*, on_recorder_msg_error, void*);
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_recorder_set_audio_read_cb,
+	struct MediaRecorderWrapper*, on_recorder_read_audio, void*);
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/properties/Makefile.am
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/properties/Makefile.am
@@ -3,6 +3,12 @@ lib_LTLIBRARIES = \
 
 libandroid_properties_la_SOURCES = properties.c cache.c
 libandroid_properties_la_CFLAGS = -I$(top_srcdir)/include $(ANDROID_HEADERS_CFLAGS)
+if WANT_RUNTIME_PROPERTY_CACHE
+libandroid_properties_la_SOURCES += runtime_cache.c
+else
+libandroid_properties_la_CFLAGS += -DNO_RUNTIME_PROPERTY_CACHE
+endif
+
 if WANT_DEBUG
 libandroid_properties_la_CFLAGS += -ggdb -O0
 endif
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/properties/properties.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/properties/properties.c
@@ -167,8 +167,23 @@ int property_get(const char *key, char *
 	if ((key) && (strlen(key) >= PROP_NAME_MAX -1)) return -1;
 	if (value == NULL) return -1;
 
-	if (property_get_socket(key, value, default_value) == 0)
-		return strlen(value);
+
+	// Runtime cache will serialize property lookups within the process.
+	// This will increase latency if multiple threads are doing many
+	// parallel lookups to new properties, but the overhead should
+	// be offset with the caching eventually.
+	runtime_cache_lock();
+	if (runtime_cache_get(key, value) == 0) {
+		ret = value;
+	} else if (property_get_socket(key, value, default_value) == 0) {
+		runtime_cache_insert(key, value);
+		ret = value;
+	}
+	runtime_cache_unlock();
+
+	if (ret)
+		return strlen(ret);
+
 
 	/* In case the socket is not available, search the property file cache by hand */
 	ret = hybris_propcache_find(key);
@@ -196,6 +211,10 @@ int property_set(const char *key, const
 	if (strlen(key) >= PROP_NAME_MAX -1) return -1;
 	if (strlen(value) >= PROP_VALUE_MAX -1) return -1;
 
+	runtime_cache_lock();
+	runtime_cache_remove(key);
+	runtime_cache_unlock();
+
 	memset(&msg, 0, sizeof(msg));
 	msg.cmd = PROP_MSG_SETPROP;
 	strncpy(msg.name, key, sizeof(msg.name));
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/properties/properties_p.h
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/properties/properties_p.h
@@ -23,4 +23,18 @@ typedef void (*hybris_propcache_list_cb)
 void hybris_propcache_list(hybris_propcache_list_cb cb, void *cookie);
 char *hybris_propcache_find(const char *key);
 
+#ifndef NO_RUNTIME_PROPERTY_CACHE
+void runtime_cache_lock();
+void runtime_cache_unlock();
+int  runtime_cache_get(const char *key, char *value);
+void runtime_cache_insert(const char *key, char *value);
+void runtime_cache_remove(const char *key);
+#else
+#define runtime_cache_lock()
+#define runtime_cache_unlock()
+#define runtime_cache_get(K,V) (-1)
+#define runtime_cache_insert(K,V)
+#define runtime_cache_remove(K)
+#endif
+
 #endif
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/properties/runtime_cache.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2012 Carsten Munk <carsten.munk@gmail.com>
+ * Copyright (c) 2008 The Android Open Source Project
+ * Copyright (c) 2013 Simon Busch <morphis@gravedo.de>
+ * Copyright (c) 2013 Canonical Ltd
+ * Copyright (c) 2013 Jolla Ltd. <robin.burchell@jollamobile.com>
+ * Copyright (c) 2015 Jolla Ltd. <mikko.harju@jollamobile.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
+
+
+#define HYBRIS_PROPERTY_CACHE_DEFAULT_TIMEOUT_SECS 10
+
+/** Maximum allowed time to return stale data from the cache. Override
+	with HYBRIS_PROPERTY_CACHE_TIMEOUT_SECS environment variable.
+*/
+static time_t runtime_cache_timeout_secs = HYBRIS_PROPERTY_CACHE_DEFAULT_TIMEOUT_SECS;
+
+
+/** Key, value pair and the time of previous update (in seconds) */
+struct hybris_prop_value
+{
+	char *key;
+	char *value;
+	time_t last_update;
+};
+
+static struct hybris_prop_value * prop_array = 0;
+static int num_prop = 0;
+static int num_alloc = 0;
+
+/** Protect access to statics */
+static pthread_mutex_t array_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* private:
+ * compares two hybris_prop_value by key, so as to maintain a qsorted array of
+ * props, and search the array.
+ */
+static int prop_qcmp(const void *a, const void *b)
+{
+	struct hybris_prop_value *aa = (struct hybris_prop_value *)a;
+	struct hybris_prop_value *bb = (struct hybris_prop_value *)b;
+
+	return strcmp(aa->key, bb->key);
+}
+
+static struct hybris_prop_value *cache_find_internal(const char *key)
+{
+	struct hybris_prop_value prop_key;
+	prop_key.key = (char*)key;
+
+	return bsearch(&prop_key, prop_array, num_prop, sizeof(struct hybris_prop_value), prop_qcmp);
+}
+
+static void runtime_cache_init()
+{
+	num_alloc = 8;
+	prop_array = malloc(num_alloc * sizeof(struct hybris_prop_value));
+
+	const char *timeout_str = getenv("HYBRIS_PROPERTY_CACHE_TIMEOUT_SECS");
+	if (timeout_str) {
+		runtime_cache_timeout_secs = atoi(timeout_str);
+	}
+}
+
+static void runtime_cache_ensure_initialized()
+{
+	if (!prop_array) {
+		runtime_cache_init();
+	}
+}
+
+/** Invalidate an entry in the cache
+  *
+  * Cache will never shrink. Instead, assume that the same key
+  * will be queried soon after invalidation and reuse the entry.
+  */
+static void runtime_cache_invalidate_entry(struct hybris_prop_value *entry)
+{
+	free(entry->value);
+	entry->value = NULL;
+}
+
+static int runtime_cache_get_impl(const char *key, char *value)
+{
+	int ret = -ENOENT;
+
+	struct hybris_prop_value *entry = cache_find_internal(key);
+	if (entry != NULL && entry->value != NULL) {
+		struct timespec now;
+		clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
+		time_t delta_secs = now.tv_sec - entry->last_update;
+		if (delta_secs > runtime_cache_timeout_secs) {
+			// assume the data in cache is stale, and force refresh
+			runtime_cache_invalidate_entry(entry);
+		} else {
+			// success, return value from cache
+			strcpy(value, entry->value);
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+static void runtime_cache_insert_impl(const char *key, char *value)
+{
+	struct timespec now;
+	clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
+
+	struct hybris_prop_value *entry = cache_find_internal(key);
+	if (entry) {
+		assert(entry->value == NULL);
+		// key,value pair was invalidated earlier,
+		// reuse entry in the property array
+		entry->value = strdup(value);
+		entry->last_update = now.tv_sec;
+	} else {
+		if (num_alloc == num_prop) {
+			num_alloc = 3 * num_alloc / 2;
+			prop_array = realloc(prop_array, num_alloc * sizeof(struct hybris_prop_value));
+		}
+
+		struct hybris_prop_value new_entry = { strdup(key), strdup(value), now.tv_sec };
+		prop_array[num_prop++] = new_entry;
+
+		qsort(prop_array, num_prop, sizeof(struct hybris_prop_value), prop_qcmp);
+	}
+}
+
+
+void runtime_cache_lock()
+{
+	pthread_mutex_lock(&array_mutex);
+}
+
+void runtime_cache_unlock()
+{
+	pthread_mutex_unlock(&array_mutex);
+}
+
+void runtime_cache_remove(const char *key)
+{
+	runtime_cache_ensure_initialized();
+	struct hybris_prop_value *entry = cache_find_internal(key);
+	if (entry) {
+		runtime_cache_invalidate_entry(entry);
+	}
+}
+
+int runtime_cache_get(const char *key, char *value)
+{
+	runtime_cache_ensure_initialized();
+	return runtime_cache_get_impl(key, value);
+}
+
+void runtime_cache_insert(const char *key, char *value)
+{
+	runtime_cache_ensure_initialized();
+	runtime_cache_insert_impl(key, value);
+}
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/tests/Makefile.am
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/Makefile.am
@@ -1,4 +1,5 @@
 bin_PROGRAMS = \
+	test_audio \
 	test_egl \
 	test_egl_configs \
 	test_glesv2 \
@@ -6,9 +7,13 @@ bin_PROGRAMS = \
 	test_sf \
 	test_sensors \
 	test_input \
+	test_lights \
 	test_camera \
 	test_vibrator \
-	test_gps
+	test_media \
+	test_recorder \
+	test_gps \
+	test_wifi
 
 if HAS_ANDROID_4_2_0
 bin_PROGRAMS += test_hwcomposer
@@ -23,14 +28,10 @@ if HAS_LIBNFC_NXP_HEADERS
 bin_PROGRAMS += test_nfc
 endif
 
-# Please re-enable your test programs according to android
-# if HAS_ANDROID_X_Y_Z
-# bin_PROGRAMS += test_audio 
-# endif
-
 test_audio_SOURCES = test_audio.c
 test_audio_CFLAGS = \
-	-I$(top_srcdir)/include
+	-I$(top_srcdir)/include \
+	-I$(top_srcdir)/include/android
 test_audio_LDADD = \
 	$(top_builddir)/common/libhybris-common.la \
 	$(top_builddir)/hardware/libhardware.la
@@ -146,6 +147,28 @@ test_camera_LDADD = \
 	$(top_builddir)/camera/libcamera.la \
 	$(top_builddir)/input/libis.la
 
+test_media_SOURCES = test_media.c
+test_media_CFLAGS = \
+	-I$(top_srcdir)/include
+test_media_LDADD = \
+	$(top_builddir)/common/libhybris-common.la \
+	$(top_builddir)/egl/libEGL.la \
+	$(top_builddir)/glesv2/libGLESv2.la \
+	$(top_builddir)/media/libmedia.la \
+	$(top_builddir)/sf/libsf.la
+
+test_recorder_SOURCES = test_recorder.c
+test_recorder_CFLAGS = \
+	-I$(top_srcdir)/include
+test_recorder_LDADD = \
+	$(top_builddir)/common/libhybris-common.la \
+	$(top_builddir)/egl/libEGL.la \
+	$(top_builddir)/glesv2/libGLESv2.la \
+	$(top_builddir)/media/libmedia.la \
+	$(top_builddir)/camera/libcamera.la \
+	$(top_builddir)/input/libis.la \
+	$(top_builddir)/sf/libsf.la
+
 test_gps_SOURCES = test_gps.c
 test_gps_CFLAGS = -pthread \
 	-I$(top_srcdir)/include \
@@ -180,3 +203,10 @@ test_vibrator_LDADD = \
 	$(top_builddir)/common/libhybris-common.la \
 	$(top_builddir)/vibrator/libvibrator.la
 
+test_wifi_SOURCES = test_wifi.c
+test_wifi_CFLAGS = \
+	-I$(top_srcdir)/include \
+	$(ANDROID_HEADERS_CFLAGS)
+test_wifi_LDADD = \
+	$(top_builddir)/wifi/libwifi.la
+
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/tests/test_audio.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_audio.c
@@ -25,32 +25,115 @@
 #include <hardware/audio.h>
 #include <hardware/hardware.h>
 
+/* Workaround for MTK */
+#define AUDIO_HARDWARE_MODULE_ID2 "libaudio"
+
 int main(int argc, char **argv)
 {
 	struct hw_module_t *hwmod = 0;
 	struct audio_hw_device *audiohw;
 
+	/* Initializing HAL */
 	hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID,
 					AUDIO_HARDWARE_MODULE_ID_PRIMARY,
 					(const hw_module_t**) &hwmod);
+	if (!hwmod) {
+		fprintf(stderr, "Failed to get hw module id: %s name: %s, trying alternative.",
+				AUDIO_HARDWARE_MODULE_ID, AUDIO_HARDWARE_MODULE_ID_PRIMARY);
+		hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID2,
+				AUDIO_HARDWARE_MODULE_ID_PRIMARY,
+				(const hw_module_t**) &hwmod);
+	}
+
 	assert(hwmod != NULL);
 
 	assert(audio_hw_device_open(hwmod, &audiohw) == 0);
+	do {
+#if defined(AUDIO_DEVICE_API_VERSION_MIN)
+		if (audiohw->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
+			fprintf(stderr, "Audio device API version %04x failed to meet minimum requirement %0x4.",
+					audiohw->common.version, AUDIO_DEVICE_API_VERSION_MIN);
+		} else
+#endif
+		if (audiohw->common.version != AUDIO_DEVICE_API_VERSION_CURRENT) {
+			fprintf(stderr, "Audio device API version %04x doesn't match platform current %0x4.",
+					audiohw->common.version, AUDIO_DEVICE_API_VERSION_CURRENT);
+		} else
+			break;
+
+#if defined(AUDIO_DEVICE_API_VERSION_MIN)
+		assert(audiohw->common.version >= AUDIO_DEVICE_API_VERSION_MIN);
+#endif
+		assert(audiohw->common.version == AUDIO_DEVICE_API_VERSION_CURRENT);
+	} while(0);
+
 	assert(audiohw->init_check(audiohw) == 0);
-	printf("Audio Hardware Interface initialized.\n");
+	fprintf(stdout, "Audio Hardware Interface initialized.\n");
 
+	/* Check volume function calls */
 	if (audiohw->get_master_volume) {
 		float volume;
 		audiohw->get_master_volume(audiohw, &volume);
-		printf("Master Volume: %f\n", volume);
+		fprintf(stdout, "Master Volume: %f\n", volume);
 	}
 
 	if (audiohw->get_master_mute) {
 		bool mute;
 		audiohw->get_master_mute(audiohw, &mute);
-		printf("Master Mute: %d\n", mute);
+		fprintf(stdout, "Master Mute: %d\n", mute);
 	}
 
+	/* Check output and input streams */
+	struct audio_config config_out = {
+		.sample_rate = 44100,
+		.channel_mask = AUDIO_CHANNEL_OUT_STEREO,
+		.format = AUDIO_FORMAT_PCM_16_BIT
+	};
+	struct audio_stream_out *stream_out = NULL;
+
+	audiohw->open_output_stream(audiohw, 0, AUDIO_DEVICE_OUT_DEFAULT,
+			AUDIO_OUTPUT_FLAG_PRIMARY, &config_out, &stream_out
+#if ANDROID_VERSION_MAJOR >= 5
+			, NULL
+#endif
+			);
+
+	/* Try it again */
+	if (!stream_out)
+		audiohw->open_output_stream(audiohw, 0, AUDIO_DEVICE_OUT_DEFAULT,
+				AUDIO_OUTPUT_FLAG_PRIMARY, &config_out, &stream_out
+#if ANDROID_VERSION_MAJOR >= 5
+				, NULL
+#endif
+				);
+
+	assert(stream_out != NULL);
+
+	fprintf(stdout, "Successfully created audio output stream: sample rate: %u, channel_mask: %u, format: %u\n",
+			config_out.sample_rate, config_out.channel_mask, config_out.format);
+
+	struct audio_config config_in = {
+		.sample_rate = 48000,
+		.channel_mask = AUDIO_CHANNEL_IN_STEREO,
+		.format = AUDIO_FORMAT_PCM_16_BIT
+	};
+	struct audio_stream_in *stream_in = NULL;
+
+	audiohw->open_input_stream(audiohw, 0, AUDIO_DEVICE_IN_DEFAULT,
+			&config_in, &stream_in
+#if ANDROID_VERSION_MAJOR >= 5
+			, AUDIO_INPUT_FLAG_NONE, NULL, AUDIO_SOURCE_DEFAULT
+#endif
+			);
+	assert(stream_in != NULL);
+
+	fprintf(stdout, "Successfully created audio input stream: sample rate: %u, channel_mask: %u, format: %u\n",
+			config_in.sample_rate, config_in.channel_mask, config_in.format);
+
+	/* Close streams and device */
+	audiohw->close_output_stream(audiohw, stream_out);
+	audiohw->close_input_stream(audiohw, stream_in);
+
 	audio_hw_device_close(audiohw);
 
 	return 0;
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/tests/test_lights.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_lights.c
@@ -30,19 +30,18 @@ int main(int argc, char **argv)
 	hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (const hw_module_t**) &hwmod);
 	assert(hwmod != NULL);
 
-	assert(light_device_open(hwmod, LIGHT_ID_NOTIFICATIONS, &notifications) == 0);
-	assert(notifications != 0);
+	hwmod->methods->open(hwmod, LIGHT_ID_NOTIFICATIONS, (hw_device_t **) &notifications);
+	assert(notifications != NULL);
 
 	memset(&notification_state, 0, sizeof(struct light_state_t));
 	notification_state.color = 0xffffffff;
 	notification_state.flashMode = LIGHT_FLASH_TIMED;
-	notification_state.flashOnMS = 1000;
+	notification_state.flashOnMS = 2000;
 	notification_state.flashOffMS = 1000;
+	notification_state.brightnessMode = BRIGHTNESS_MODE_USER;
 
 	assert(notifications->set_light(notifications, &notification_state) == 0);
 
-	light_device_close(notifications);
-
 	return 0;
 }
 
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_media.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ */
+
+#include <hybris/media/media_compatibility_layer.h>
+#include <hybris/surface_flinger/surface_flinger_compatibility_layer.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+enum {
+	OK          = 0,
+	NO_ERROR    = 0,
+};
+
+static float DestWidth = 0.0, DestHeight = 0.0;
+// Actual video dimmensions
+static int Width = 0, Height = 0;
+
+static GLuint gProgram;
+static GLuint gaPositionHandle, gaTexHandle, gsTextureHandle, gmTexMatrix;
+
+static GLfloat positionCoordinates[8];
+
+struct MediaPlayerWrapper *player = NULL;
+
+void calculate_position_coordinates()
+{
+	// Assuming cropping output for now
+	float x = 1, y = 1;
+
+	// Black borders
+	x = (float) (Width / DestWidth);
+	y = (float) (Height / DestHeight);
+
+	// Make the larger side be 1
+	if (x > y) {
+		y /= x;
+		x = 1;
+	} else {
+		x /= y;
+		y = 1;
+	}
+
+	positionCoordinates[0] = -x;
+	positionCoordinates[1] = y;
+	positionCoordinates[2] = -x;
+	positionCoordinates[3] = -y;
+	positionCoordinates[4] = x;
+	positionCoordinates[5] = -y;
+	positionCoordinates[6] = x;
+	positionCoordinates[7] = y;
+}
+
+struct ClientWithSurface
+{
+	struct SfClient* client;
+	struct SfSurface* surface;
+};
+
+struct ClientWithSurface client_with_surface(bool setup_surface_with_egl)
+{
+	struct ClientWithSurface cs;
+
+	cs.client = sf_client_create();
+
+	if (!cs.client) {
+		printf("Problem creating client ... aborting now.");
+		return cs;
+	}
+
+	static const size_t primary_display = 0;
+
+	DestWidth = sf_get_display_width(primary_display);
+	DestHeight = sf_get_display_height(primary_display);
+	printf("Primary display width: %f, height: %f\n", DestWidth, DestHeight);
+
+	SfSurfaceCreationParameters params = {
+		0,
+		0,
+		DestWidth,
+		DestHeight,
+		-1, //PIXEL_FORMAT_RGBA_8888,
+		15000,
+		0.5f,
+		setup_surface_with_egl, // Do not associate surface with egl, will be done by camera HAL
+		"MediaCompatLayerTestSurface"
+	};
+
+	cs.surface = sf_surface_create(cs.client, &params);
+
+	if (!cs.surface) {
+		printf("Problem creating surface ... aborting now.");
+		return cs;
+	}
+
+	sf_surface_make_current(cs.surface);
+
+	return cs;
+}
+
+static const char *vertex_shader()
+{
+	return
+		"attribute vec4 a_position;                                  \n"
+		"attribute vec2 a_texCoord;                                  \n"
+		"uniform mat4 m_texMatrix;                                   \n"
+		"varying vec2 v_texCoord;                                    \n"
+		"varying float topDown;                                      \n"
+		"void main()                                                 \n"
+		"{                                                           \n"
+		"   gl_Position = a_position;                                \n"
+		"   v_texCoord = (m_texMatrix * vec4(a_texCoord, 0.0, 1.0)).xy;\n"
+		"}                                                           \n";
+}
+
+static const char *fragment_shader()
+{
+	return
+		"#extension GL_OES_EGL_image_external : require      \n"
+		"precision mediump float;                            \n"
+		"varying vec2 v_texCoord;                            \n"
+		"uniform samplerExternalOES s_texture;               \n"
+		"void main()                                         \n"
+		"{                                                   \n"
+		"  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
+		"}                                                   \n";
+}
+
+static GLuint loadShader(GLenum shaderType, const char* pSource)
+{
+	GLuint shader = glCreateShader(shaderType);
+
+	if (shader) {
+		glShaderSource(shader, 1, &pSource, NULL);
+		glCompileShader(shader);
+		GLint compiled = 0;
+		glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+
+		if (!compiled) {
+			GLint infoLen = 0;
+			glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+			if (infoLen) {
+				char* buf = (char*) malloc(infoLen);
+				if (buf) {
+					glGetShaderInfoLog(shader, infoLen, NULL, buf);
+					fprintf(stderr, "Could not compile shader %d:\n%s\n",
+							shaderType, buf);
+					free(buf);
+				}
+				glDeleteShader(shader);
+				shader = 0;
+			}
+		}
+	} else {
+		printf("Error, during shader creation: %i\n", glGetError());
+	}
+
+	return shader;
+}
+
+static GLuint create_program(const char* pVertexSource, const char* pFragmentSource)
+{
+	GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+	if (!vertexShader) {
+		printf("vertex shader not compiled\n");
+		return 0;
+	}
+
+	GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+	if (!pixelShader) {
+		printf("frag shader not compiled\n");
+		return 0;
+	}
+
+	GLuint program = glCreateProgram();
+	if (program) {
+		glAttachShader(program, vertexShader);
+		glAttachShader(program, pixelShader);
+		glLinkProgram(program);
+		GLint linkStatus = GL_FALSE;
+
+		glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+		if (linkStatus != GL_TRUE) {
+			GLint bufLength = 0;
+			glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+			if (bufLength) {
+				char* buf = (char*) malloc(bufLength);
+				if (buf) {
+					glGetProgramInfoLog(program, bufLength, NULL, buf);
+					fprintf(stderr, "Could not link program:\n%s\n", buf);
+					free(buf);
+				}
+			}
+			glDeleteProgram(program);
+			program = 0;
+		}
+	}
+
+	return program;
+}
+
+static int setup_video_texture(struct ClientWithSurface *cs, GLuint *preview_texture_id)
+{
+	assert(cs != NULL);
+	assert(preview_texture_id != NULL);
+
+	sf_surface_make_current(cs->surface);
+
+	glGenTextures(1, preview_texture_id);
+	glClearColor(0, 0, 0, 0);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+	android_media_set_preview_texture(player, *preview_texture_id);
+
+	return 0;
+}
+
+void set_video_size_cb(int height, int width, void *context)
+{
+	printf("Video height: %d, width: %d\n", height, width);
+	printf("Video dest height: %f, width: %f\n", DestHeight, DestWidth);
+
+	Height = height;
+	Width = width;
+}
+
+void media_prepared_cb(void *context)
+{
+	printf("Media is prepared for playback.\n");
+}
+
+int main(int argc, char **argv)
+{
+	if (argc < 2) {
+		printf("Usage: test_media <video_to_play>\n");
+		return EXIT_FAILURE;
+	}
+
+	player = android_media_new_player();
+	if (player == NULL) {
+		printf("Problem creating new media player.\n");
+		return EXIT_FAILURE;
+	}
+
+	// Set player event cb for when the video size is known:
+	android_media_set_video_size_cb(player, set_video_size_cb, NULL);
+	android_media_set_media_prepared_cb(player, media_prepared_cb, NULL);
+
+	printf("Setting data source to: %s.\n", argv[1]);
+
+	if (android_media_set_data_source(player, argv[1]) != OK) {
+		printf("Failed to set data source: %s\n", argv[1]);
+		return EXIT_FAILURE;
+	}
+
+	printf("Creating EGL surface.\n");
+	struct ClientWithSurface cs = client_with_surface(true /* Associate surface with egl. */);
+	if (!cs.surface) {
+		printf("Problem acquiring surface for preview");
+		return EXIT_FAILURE;
+	}
+
+	printf("Creating GL texture.\n");
+
+	GLuint preview_texture_id;
+	EGLDisplay disp = sf_client_get_egl_display(cs.client);
+	EGLSurface surface = sf_surface_get_egl_surface(cs.surface);
+
+	sf_surface_make_current(cs.surface);
+
+	if (setup_video_texture(&cs, &preview_texture_id) != OK) {
+		printf("Problem setting up GL texture for video surface.\n");
+		return EXIT_FAILURE;
+	}
+
+	printf("Starting video playback.\n");
+	android_media_play(player);
+
+	while (android_media_is_playing(player)) {
+		GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+		const GLfloat textureCoordinates[] = {
+			1.0f,  1.0f,
+			0.0f,  1.0f,
+			0.0f,  0.0f,
+			1.0f,  0.0f
+		};
+
+		android_media_update_surface_texture(player);
+
+		calculate_position_coordinates();
+
+		gProgram = create_program(vertex_shader(), fragment_shader());
+		gaPositionHandle = glGetAttribLocation(gProgram, "a_position");
+		gaTexHandle = glGetAttribLocation(gProgram, "a_texCoord");
+		gsTextureHandle = glGetUniformLocation(gProgram, "s_texture");
+		gmTexMatrix = glGetUniformLocation(gProgram, "m_texMatrix");
+
+		glClear(GL_COLOR_BUFFER_BIT);
+
+		// Use the program object
+		glUseProgram(gProgram);
+		// Enable attributes
+		glEnableVertexAttribArray(gaPositionHandle);
+		glEnableVertexAttribArray(gaTexHandle);
+		// Load the vertex position
+		glVertexAttribPointer(gaPositionHandle,
+				2,
+				GL_FLOAT,
+				GL_FALSE,
+				0,
+				positionCoordinates);
+		// Load the texture coordinate
+		glVertexAttribPointer(gaTexHandle,
+				2,
+				GL_FLOAT,
+				GL_FALSE,
+				0,
+				textureCoordinates);
+
+		GLfloat matrix[16];
+		android_media_surface_texture_get_transformation_matrix(player, matrix);
+
+		glUniformMatrix4fv(gmTexMatrix, 1, GL_FALSE, matrix);
+
+		glActiveTexture(GL_TEXTURE0);
+		// Set the sampler texture unit to 0
+		glUniform1i(gsTextureHandle, 0);
+		glUniform1i(gmTexMatrix, 0);
+		android_media_update_surface_texture(player);
+		glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+		//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+		glDisableVertexAttribArray(gaPositionHandle);
+		glDisableVertexAttribArray(gaTexHandle);
+
+		eglSwapBuffers(disp, surface);
+	}
+
+	android_media_stop(player);
+
+	return EXIT_SUCCESS;
+}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_recorder.c
@@ -0,0 +1,490 @@
+/*
+ * Copyright (C) 2013 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com>
+ *              Guenter Schwann <guenter.schwann@canonical.com>
+ *              Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
+ */
+
+#include <hybris/camera/camera_compatibility_layer.h>
+#include <hybris/camera/camera_compatibility_layer_capabilities.h>
+
+#include <hybris/media/recorder_compatibility_layer.h>
+
+#include <hybris/input/input_stack_compatibility_layer.h>
+#include <hybris/input/input_stack_compatibility_layer_codes_key.h>
+#include <hybris/input/input_stack_compatibility_layer_flags_key.h>
+
+#include <hybris/surface_flinger/surface_flinger_compatibility_layer.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+int shot_counter = 1;
+int32_t current_zoom_level = 1;
+bool new_camera_frame_available = true;
+struct MediaRecorderWrapper *mr = 0;
+GLuint preview_texture_id = 0;
+
+static GLuint gProgram;
+static GLuint gaPositionHandle, gaTexHandle, gsTextureHandle, gmTexMatrix;
+
+void error_msg_cb(void* context)
+{
+	printf("%s \n", __PRETTY_FUNCTION__);
+}
+
+void shutter_msg_cb(void* context)
+{
+	printf("%s \n", __PRETTY_FUNCTION__);
+}
+
+void zoom_msg_cb(void* context, int32_t new_zoom_level)
+{
+	printf("%s \n", __PRETTY_FUNCTION__);
+
+	struct CameraControl* cc = (struct CameraControl*) context;
+	static int zoom;
+	current_zoom_level = new_zoom_level;
+}
+
+void autofocus_msg_cb(void* context)
+{
+	printf("%s \n", __PRETTY_FUNCTION__);
+}
+
+void raw_data_cb(void* data, uint32_t data_size, void* context)
+{
+	printf("%s: %d \n", __PRETTY_FUNCTION__, data_size);
+}
+
+void jpeg_data_cb(void* data, uint32_t data_size, void* context)
+{
+	printf("%s: %d \n", __PRETTY_FUNCTION__, data_size);
+	struct CameraControl* cc = (struct CameraControl*) context;
+	android_camera_start_preview(cc);
+}
+
+void size_cb(void* ctx, int width, int height)
+{
+	printf("Supported size: [%d,%d]\n", width, height);
+}
+
+void preview_texture_needs_update_cb(void* ctx)
+{
+	new_camera_frame_available = true;
+}
+
+void on_new_input_event(struct Event* event, void* context)
+{
+	assert(context);
+
+	if (event->type == KEY_EVENT_TYPE && event->action == ISCL_KEY_EVENT_ACTION_UP) {
+		printf("We have got a key event: %d \n", event->details.key.key_code);
+
+		struct CameraControl* cc = (struct CameraControl*) context;
+
+		int ret;
+		switch (event->details.key.key_code) {
+		case ISCL_KEYCODE_VOLUME_UP:
+			printf("Starting video recording\n");
+
+			android_camera_unlock(cc);
+
+			ret = android_recorder_setCamera(mr, cc);
+			if (ret < 0) {
+				printf("android_recorder_setCamera() failed\n");
+				return;
+			}
+			//state initial / idle
+			ret = android_recorder_setAudioSource(mr, ANDROID_AUDIO_SOURCE_CAMCORDER);
+			if (ret < 0) {
+				printf("android_recorder_setAudioSource() failed\n");
+				return;
+			}
+			ret = android_recorder_setVideoSource(mr, ANDROID_VIDEO_SOURCE_CAMERA);
+			if (ret < 0) {
+				printf("android_recorder_setVideoSource() failed\n");
+				return;
+			}
+			//state initialized
+			ret = android_recorder_setOutputFormat(mr, ANDROID_OUTPUT_FORMAT_MPEG_4);
+			if (ret < 0) {
+				printf("android_recorder_setOutputFormat() failed\n");
+				return;
+			}
+			//state DataSourceConfigured
+			ret = android_recorder_setAudioEncoder(mr, ANDROID_AUDIO_ENCODER_AAC);
+			if (ret < 0) {
+				printf("android_recorder_setAudioEncoder() failed\n");
+				return;
+			}
+			ret = android_recorder_setVideoEncoder(mr, ANDROID_VIDEO_ENCODER_H264);
+			if (ret < 0) {
+				printf("android_recorder_setVideoEncoder() failed\n");
+				return;
+			}
+
+			int fd;
+			fd = open("/tmp/test_video_recorder.avi", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+			if (fd < 0) {
+				printf("Could not open file for video recording\n");
+				printf("FD: %i\n", fd);
+				return;
+			}
+			ret = android_recorder_setOutputFile(mr, fd);
+			if (ret < 0) {
+				printf("android_recorder_setOutputFile() failed\n");
+				return;
+			}
+
+			ret = android_recorder_setVideoSize(mr, 1280, 720);
+			if (ret < 0) {
+				printf("android_recorder_setVideoSize() failed\n");
+				return;
+			}
+			ret = android_recorder_setVideoFrameRate(mr, 30);
+			if (ret < 0) {
+				printf("android_recorder_setVideoFrameRate() failed\n");
+				return;
+			}
+
+			ret = android_recorder_prepare(mr);
+			if (ret < 0) {
+				printf("android_recorder_prepare() failed\n");
+				return;
+			}
+			//state prepared
+			ret = android_recorder_start(mr);
+			if (ret < 0) {
+				printf("android_recorder_start() failed\n");
+				return;
+			}
+			break;
+		case ISCL_KEYCODE_VOLUME_DOWN:
+			printf("Stoping video recording\n");
+			ret = android_recorder_stop(mr);
+
+			printf("Stoping video recording returned\n");
+			if (ret < 0) {
+				printf("android_recorder_stop() failed\n");
+				return;
+			}
+			printf("Stopped video recording\n");
+			ret = android_recorder_reset(mr);
+			if (ret < 0) {
+				printf("android_recorder_reset() failed\n");
+				return;
+			}
+			printf("Reset video recorder\n");
+			break;
+		}
+	}
+}
+
+struct ClientWithSurface
+{
+	struct SfClient* client;
+	struct SfSurface* surface;
+};
+
+struct ClientWithSurface client_with_surface(bool setup_surface_with_egl)
+{
+	struct ClientWithSurface cs;
+
+	cs.client = sf_client_create();
+
+	if (!cs.client) {
+		printf("Problem creating client ... aborting now.");
+		return cs;
+	}
+
+	static const size_t primary_display = 0;
+
+	SfSurfaceCreationParameters params = {
+		0,
+		0,
+		sf_get_display_width(primary_display),
+		sf_get_display_height(primary_display),
+		-1, //PIXEL_FORMAT_RGBA_8888,
+		15000,
+		0.5f,
+		setup_surface_with_egl, // Do not associate surface with egl, will be done by camera HAL
+		"CameraCompatLayerTestSurface"
+	};
+
+	cs.surface = sf_surface_create(cs.client, &params);
+
+	if (!cs.surface) {
+		printf("Problem creating surface ... aborting now.");
+		return cs;
+	}
+
+	sf_surface_make_current(cs.surface);
+
+	return cs;
+}
+
+static const char* vertex_shader()
+{
+	return
+		"#extension GL_OES_EGL_image_external : require              \n"
+		"attribute vec4 a_position;                                  \n"
+		"attribute vec2 a_texCoord;                                  \n"
+		"uniform mat4 m_texMatrix;                                   \n"
+		"varying vec2 v_texCoord;                                    \n"
+		"varying float topDown;                                      \n"
+		"void main()                                                 \n"
+		"{                                                           \n"
+		"   gl_Position = a_position;                                \n"
+		"   v_texCoord = a_texCoord;                                 \n"
+		//                "   v_texCoord = (m_texMatrix * vec4(a_texCoord, 0.0, 1.0)).xy;\n"
+		//"   topDown = v_texCoord.y;                                  \n"
+		"}                                                           \n";
+}
+
+static const char* fragment_shader()
+{
+	return
+		"#extension GL_OES_EGL_image_external : require      \n"
+		"precision mediump float;                            \n"
+		"varying vec2 v_texCoord;                            \n"
+		"uniform samplerExternalOES s_texture;               \n"
+		"void main()                                         \n"
+		"{                                                   \n"
+		"  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
+		"}                                                   \n";
+}
+
+static GLuint loadShader(GLenum shaderType, const char* pSource) {
+	GLuint shader = glCreateShader(shaderType);
+
+	if (shader) {
+		glShaderSource(shader, 1, &pSource, NULL);
+		glCompileShader(shader);
+		GLint compiled = 0;
+		glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+
+		if (!compiled) {
+			GLint infoLen = 0;
+			glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+			if (infoLen) {
+				char* buf = (char*) malloc(infoLen);
+				if (buf) {
+					glGetShaderInfoLog(shader, infoLen, NULL, buf);
+					fprintf(stderr, "Could not compile shader %d:\n%s\n",
+							shaderType, buf);
+					free(buf);
+				}
+				glDeleteShader(shader);
+				shader = 0;
+			}
+		}
+	} else {
+		printf("Error, during shader creation: %i\n", glGetError());
+	}
+
+	return shader;
+}
+
+static GLuint create_program(const char* pVertexSource, const char* pFragmentSource) {
+	GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+	if (!vertexShader) {
+		printf("vertex shader not compiled\n");
+		return 0;
+	}
+
+	GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+	if (!pixelShader) {
+		printf("frag shader not compiled\n");
+		return 0;
+	}
+
+	GLuint program = glCreateProgram();
+	if (program) {
+		glAttachShader(program, vertexShader);
+		glAttachShader(program, pixelShader);
+		glLinkProgram(program);
+		GLint linkStatus = GL_FALSE;
+
+		glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+		if (linkStatus != GL_TRUE) {
+			GLint bufLength = 0;
+			glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+			if (bufLength) {
+				char* buf = (char*) malloc(bufLength);
+				if (buf) {
+					glGetProgramInfoLog(program, bufLength, NULL, buf);
+					fprintf(stderr, "Could not link program:\n%s\n", buf);
+					free(buf);
+				}
+			}
+			glDeleteProgram(program);
+			program = 0;
+		}
+	}
+
+	return program;
+}
+
+int main(int argc, char** argv)
+{
+	printf("Test application for video recording using the camera\n");
+	printf("Recording start with volume up button. And stops with volume down.\n");
+	printf("The result is stored to /root/test_video.avi\n\n");
+
+	struct CameraControlListener listener;
+	memset(&listener, 0, sizeof(listener));
+	listener.on_msg_error_cb = error_msg_cb;
+	listener.on_msg_shutter_cb = shutter_msg_cb;
+	listener.on_msg_focus_cb = autofocus_msg_cb;
+	listener.on_msg_zoom_cb = zoom_msg_cb;
+
+	listener.on_data_raw_image_cb = raw_data_cb;
+	listener.on_data_compressed_image_cb = jpeg_data_cb;
+	listener.on_preview_texture_needs_update_cb = preview_texture_needs_update_cb;
+	struct CameraControl* cc = android_camera_connect_to(BACK_FACING_CAMERA_TYPE,
+			&listener);
+	if (cc == NULL) {
+		printf("Problem connecting to camera");
+		return 1;
+	}
+
+	listener.context = cc;
+
+	mr = android_media_new_recorder();
+
+	struct AndroidEventListener event_listener;
+	event_listener.on_new_event = on_new_input_event;
+	event_listener.context = cc;
+
+	struct InputStackConfiguration input_configuration = { false, 25000 };
+
+	android_input_stack_initialize(&event_listener, &input_configuration);
+	android_input_stack_start();
+
+	android_camera_dump_parameters(cc);
+
+	printf("Supported video sizes:\n");
+	android_camera_enumerate_supported_video_sizes(cc, size_cb, NULL);
+
+	int min_fps, max_fps, current_fps;
+
+	android_camera_set_preview_size(cc, 1280, 720);
+
+	int width, height;
+	android_camera_get_video_size(cc, &width, &height);
+	printf("Current video size: [%d,%d]\n", width, height);
+
+	struct ClientWithSurface cs = client_with_surface(true /* Associate surface with egl. */);
+
+	if (!cs.surface) {
+		printf("Problem acquiring surface for preview");
+		return 1;
+	}
+
+	EGLDisplay disp = sf_client_get_egl_display(cs.client);
+	EGLSurface surface = sf_surface_get_egl_surface(cs.surface);
+
+	sf_surface_make_current(cs.surface);
+
+	gProgram = create_program(vertex_shader(), fragment_shader());
+	gaPositionHandle = glGetAttribLocation(gProgram, "a_position");
+	gaTexHandle = glGetAttribLocation(gProgram, "a_texCoord");
+	gsTextureHandle = glGetUniformLocation(gProgram, "s_texture");
+	gmTexMatrix = glGetUniformLocation(gProgram, "m_texMatrix");
+
+	glGenTextures(1, &preview_texture_id);
+	glClearColor(1.0, 0., 0.5, 1.);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameteri(
+			GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(
+			GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	android_camera_set_preview_texture(cc, preview_texture_id);
+	android_camera_start_preview(cc);
+
+	GLfloat transformation_matrix[16];
+	android_camera_get_preview_texture_transformation(cc, transformation_matrix);
+	glUniformMatrix4fv(gmTexMatrix, 1, GL_FALSE, transformation_matrix);
+
+	printf("Started camera preview.\n");
+
+	while (true) {
+		/*if (new_camera_frame_available)
+		  {
+		  printf("Updating texture");
+		  new_camera_frame_available = false;
+		  }*/
+		static GLfloat vVertices[] = { 0.0f, 0.0f, 0.0f, // Position 0
+			0.0f, 0.0f, // TexCoord 0
+			0.0f, 1.0f, 0.0f, // Position 1
+			0.0f, 1.0f, // TexCoord 1
+			1.0f, 1.0f, 0.0f, // Position 2
+			1.0f, 1.0f, // TexCoord 2
+			1.0f, 0.0f, 0.0f, // Position 3
+			1.0f, 0.0f // TexCoord 3
+		};
+
+		GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+		// Set the viewport
+		// Clear the color buffer
+		glClear(GL_COLOR_BUFFER_BIT);
+		// Use the program object
+		glUseProgram(gProgram);
+		// Enable attributes
+		glEnableVertexAttribArray(gaPositionHandle);
+		glEnableVertexAttribArray(gaTexHandle);
+		// Load the vertex position
+		glVertexAttribPointer(gaPositionHandle,
+				3,
+				GL_FLOAT,
+				GL_FALSE,
+				5 * sizeof(GLfloat),
+				vVertices);
+		// Load the texture coordinate
+		glVertexAttribPointer(gaTexHandle,
+				2,
+				GL_FLOAT,
+				GL_FALSE,
+				5 * sizeof(GLfloat),
+				vVertices+3);
+
+		glActiveTexture(GL_TEXTURE0);
+		// Set the sampler texture unit to 0
+		glUniform1i(gsTextureHandle, 0);
+		glUniform1i(gmTexMatrix, 0);
+		android_camera_update_preview_texture(cc);
+		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+		glDisableVertexAttribArray(gaPositionHandle);
+		glDisableVertexAttribArray(gaTexHandle);
+
+		eglSwapBuffers(disp, surface);
+	}
+}
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/tests/test_ui.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_ui.c
@@ -53,8 +53,10 @@ int main(int argc, char **argv)
 	graphic_buffer_lock(buffer, GRALLOC_USAGE_HW_RENDER, &vaddr);
 	graphic_buffer_unlock(buffer);
 
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
 	graphic_buffer_set_index(buffer, 11);
 	assert(graphic_buffer_get_index(buffer) == 11);
+#endif
 
 	graphic_buffer_free(buffer);
 
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/tests/test_wifi.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+
+#include <android-config.h>
+#include <hardware_legacy/wifi.h>
+
+#define COMMAND_LOAD_WIFI "1"
+#define COMMAND_UNLOAD_WIFI "0"
+
+int main(int argc, char **argv)
+{
+	if (argc < 2) {
+		fprintf(stdout, "To load driver: %s " COMMAND_LOAD_WIFI "\n", argv[0]);
+		fprintf(stdout, "To unload driver: %s " COMMAND_UNLOAD_WIFI "\n", argv[0]);
+	} else {
+		int ret;
+
+		if (strcmp(argv[1], COMMAND_LOAD_WIFI) == 0) {
+			if ((ret = wifi_load_driver()) < 0)
+				fprintf(stderr, "Cannot load driver (err %d)\n", ret);
+			else
+				fprintf(stdout, "Driver loaded\n");
+		} else if (strcmp(argv[1], COMMAND_UNLOAD_WIFI) == 0) {
+			if ((ret = wifi_unload_driver()) < 0)
+				fprintf(stderr, "Cannot unload driver (err %d)\n", ret);
+			else
+				fprintf(stdout, "Driver unloaded\n");
+		} else {
+			fprintf(stderr, "Wrong command\n");
+			return 1;
+		}
+	}
+
+	fprintf(stdout, "WiFi driver load state: %d\n", is_wifi_driver_loaded());
+
+	return 0;
+}
+
+// vim:ts=4:sw=4:noexpandtab
--- libhybris-0.1.0+git20151016+6d424c9.orig/hybris/ui/ui.c
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/ui/ui.c
@@ -48,9 +48,11 @@ HYBRIS_IMPLEMENT_FUNCTION1(ui, uint32_t,
 	struct graphic_buffer*);
 HYBRIS_IMPLEMENT_FUNCTION1(ui, void*, graphic_buffer_get_native_buffer,
 	struct graphic_buffer*);
+#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=3
 HYBRIS_IMPLEMENT_VOID_FUNCTION2(ui, graphic_buffer_set_index,
 	struct graphic_buffer*, int);
 HYBRIS_IMPLEMENT_FUNCTION1(ui, int, graphic_buffer_get_index,
 	struct graphic_buffer*);
+#endif
 HYBRIS_IMPLEMENT_FUNCTION1(ui, int, graphic_buffer_init_check,
 	struct graphic_buffer*);
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/wifi/Makefile.am
@@ -0,0 +1,17 @@
+lib_LTLIBRARIES = \
+	libwifi.la
+
+libwifi_la_SOURCES = wifi.c
+libwifi_la_CFLAGS = -I$(top_srcdir)/include
+if WANT_TRACE
+libwifi_la_CFLAGS += -DDEBUG
+endif
+if WANT_DEBUG
+libwifi_la_CFLAGS += -ggdb -O0
+endif
+libwifi_la_LDFLAGS = \
+	$(top_builddir)/common/libhybris-common.la \
+	-version-info "1":"0":"0"
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libwifi.pc
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/wifi/libwifi.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=@libdir@
+includedir=@includedir@
+
+Name: hybris-wifi
+Description: libhybris wifi library
+Version: @VERSION@
+Libs: -L${libdir} -lhybris-common -lwifi
+Cflags: -I${includedir}
--- /dev/null
+++ libhybris-0.1.0+git20151016+6d424c9/hybris/wifi/wifi.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authored by: Alfonso Sanchez-Beato <alfonso.sanchez-beato@canonical.com>
+ */
+
+#include <dlfcn.h>
+#include <stddef.h>
+
+#include <hybris/common/binding.h>
+#include <hardware_legacy/wifi.h>
+
+#define COMPAT_LIBRARY_PATH "/system/lib/libhardware_legacy.so"
+
+HYBRIS_LIBRARY_INITIALIZE(wifi, COMPAT_LIBRARY_PATH);
+
+int wifi_compat_check_availability()
+{
+    /* Both are defined via HYBRIS_LIBRARY_INITIALIZE */
+    hybris_wifi_initialize();
+    return wifi_handle ? 1 : 0;
+}
+
+HYBRIS_IMPLEMENT_FUNCTION0(wifi, int, wifi_load_driver);
+HYBRIS_IMPLEMENT_FUNCTION0(wifi, int, wifi_unload_driver);
+HYBRIS_IMPLEMENT_FUNCTION0(wifi, int, is_wifi_driver_loaded);
+HYBRIS_IMPLEMENT_FUNCTION1(wifi, int, wifi_start_supplicant, int);
+HYBRIS_IMPLEMENT_FUNCTION1(wifi, int, wifi_stop_supplicant, int);
+HYBRIS_IMPLEMENT_FUNCTION0(wifi, int, wifi_connect_to_supplicant);
+HYBRIS_IMPLEMENT_VOID_FUNCTION0(wifi, wifi_close_supplicant_connection);
+HYBRIS_IMPLEMENT_FUNCTION2(wifi, int, wifi_wait_for_event, char *, size_t);
+HYBRIS_IMPLEMENT_FUNCTION3(wifi, int, wifi_command,
+				const char *, char *, size_t *);
+HYBRIS_IMPLEMENT_FUNCTION7(wifi, int, do_dhcp_request, int *, int *, int *,
+				int *, int *, int *, int *);
+HYBRIS_IMPLEMENT_FUNCTION0(wifi, const char *, get_dhcp_error_string);
+HYBRIS_IMPLEMENT_FUNCTION1(wifi, const char *, wifi_get_fw_path, int);
+HYBRIS_IMPLEMENT_FUNCTION1(wifi, int, wifi_change_fw_path, const char *);
+HYBRIS_IMPLEMENT_FUNCTION0(wifi, int, ensure_entropy_file_exists);
--- libhybris-0.1.0+git20151016+6d424c9.orig/utils/generate_wrapper_macros.py
+++ libhybris-0.1.0+git20151016+6d424c9/utils/generate_wrapper_macros.py
@@ -104,6 +104,12 @@ print """
         name##_handle = android_dlopen(path, RTLD_LAZY); \\
     }
 
+#define HYBRIS_LIRBARY_CHECK_SYMBOL(name) \\
+    bool hybris_##name##_check_for_symbol(const char *sym) \\
+    { \\
+        return android_dlsym(name##_handle, sym) != NULL; \\
+    }
+
 """
 
 for count in range(MAX_ARGS):
