diff --git a/src/multimedia/multimedia.pro b/src/multimedia/multimedia.pro
index f1f4b3896d6146dc3102864f285e422495f0e8b2..54c6e0a9b24aa4c67671273e490251e6acfd2a56 100644
--- a/src/multimedia/multimedia.pro
+++ b/src/multimedia/multimedia.pro
@@ -52,11 +52,11 @@ include(recording/recording.pri)
 include(video/video.pri)
 
 ANDROID_BUNDLED_JAR_DEPENDENCIES = \
-    jar/QtMultimedia-bundled.jar
+    jar/QtMultimedia-bundled.jar:org.qtproject.qt5.android.multimedia.QtMultimediaUtils
 ANDROID_JAR_DEPENDENCIES = \
-    jar/QtMultimedia.jar
+    jar/QtMultimedia.jar:org.qtproject.qt5.android.multimedia.QtMultimediaUtils
 ANDROID_LIB_DEPENDENCIES = \
-    plugins/mediaservice/libandroidmediaplayer.so \
+    plugins/mediaservice/libqtmedia_android.so \
     lib/libQt5MultimediaQuick_p.so:Qt5Quick
 ANDROID_BUNDLED_FILES += \
     lib/libQt5MultimediaQuick_p.so
diff --git a/src/plugins/android/android.pro b/src/plugins/android/android.pro
index 2cfc83f0e9e94221e9c1c9e828b9c0f9d16bf12e..288ae8528da4cbe4f5c257e34f1b8628895f4933 100644
--- a/src/plugins/android/android.pro
+++ b/src/plugins/android/android.pro
@@ -1,5 +1,5 @@
 TEMPLATE = subdirs
 
-SUBDIRS += mediaplayer \
+SUBDIRS += src \
            jar
 
diff --git a/src/plugins/android/jar/jar.pri b/src/plugins/android/jar/jar.pri
index e6a3c63c2edf0bff7d8ad2be1df61ad823f3fe69..9e235144b6d2dfa88f506fe730918fc078571f42 100644
--- a/src/plugins/android/jar/jar.pri
+++ b/src/plugins/android/jar/jar.pri
@@ -6,9 +6,14 @@ API_VERSION = android-11
 JAVACLASSPATH += $$PWD/src
 
 JAVASOURCES += $$PWD/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java \
+               $$PWD/src/org/qtproject/qt5/android/multimedia/QtCamera.java \
                $$PWD/src/org/qtproject/qt5/android/multimedia/QtSurfaceTexture.java \
-               $$PWD/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder.java
+               $$PWD/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder.java \
+               $$PWD/src/org/qtproject/qt5/android/multimedia/QtMultimediaUtils.java \
+               $$PWD/src/org/qtproject/qt5/android/multimedia/QtMediaRecorder.java
 
 # install
 target.path = $$[QT_INSTALL_PREFIX]/jar
 INSTALLS += target
+
+OTHER_FILES += $$JAVASOURCES
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java
new file mode 100644
index 0000000000000000000000000000000000000000..b0a4954cfd0b70ae86079ba770c2a2857d42a120
--- /dev/null
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java
@@ -0,0 +1,182 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtMultimedia module of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:LGPL$
+ ** Commercial License Usage
+ ** Licensees holding valid commercial Qt licenses may use this file in
+ ** accordance with the commercial license agreement provided with the
+ ** Software or, alternatively, in accordance with the terms contained in
+ ** a written agreement between you and Digia.  For licensing terms and
+ ** conditions see http://qt.digia.com/licensing.  For further information
+ ** use the contact form at http://qt.digia.com/contact-us.
+ **
+ ** GNU Lesser General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU Lesser
+ ** General Public License version 2.1 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.LGPL included in the
+ ** packaging of this file.  Please review the following information to
+ ** ensure the GNU Lesser General Public License version 2.1 requirements
+ ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ **
+ ** In addition, as a special exception, Digia gives you certain additional
+ ** rights.  These rights are described in the Digia Qt LGPL Exception
+ ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+ **
+ ** GNU General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU
+ ** General Public License version 3.0 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.GPL included in the
+ ** packaging of this file.  Please review the following information to
+ ** ensure the GNU General Public License version 3.0 requirements will be
+ ** met: http://www.gnu.org/copyleft/gpl.html.
+ **
+ **
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+package org.qtproject.qt5.android.multimedia;
+
+import android.hardware.Camera;
+import android.graphics.SurfaceTexture;
+import android.util.Log;
+
+public class QtCamera implements Camera.ShutterCallback, Camera.PictureCallback, Camera.AutoFocusCallback
+{
+    private int m_cameraId = -1;
+    private Camera m_camera = null;
+
+    private static final String TAG = "Qt Camera";
+
+    private QtCamera(int id, Camera cam)
+    {
+        m_cameraId = id;
+        m_camera = cam;
+    }
+
+    public static QtCamera open(int cameraId)
+    {
+        try {
+            Camera cam = Camera.open(cameraId);
+            return new QtCamera(cameraId, cam);
+        } catch(Exception e) {
+            Log.d(TAG, e.getMessage());
+        }
+        return null;
+    }
+
+    public Camera.Parameters getParameters()
+    {
+        return m_camera.getParameters();
+    }
+
+    public void lock()
+    {
+        try {
+            m_camera.lock();
+        } catch(Exception e) {
+            Log.d(TAG, e.getMessage());
+        }
+    }
+
+    public void unlock()
+    {
+        try {
+            m_camera.unlock();
+        } catch(Exception e) {
+            Log.d(TAG, e.getMessage());
+        }
+    }
+
+    public void release()
+    {
+        m_camera.release();
+    }
+
+    public void reconnect()
+    {
+        try {
+            m_camera.reconnect();
+        } catch(Exception e) {
+            Log.d(TAG, e.getMessage());
+        }
+    }
+
+    public void setDisplayOrientation(int degrees)
+    {
+        m_camera.setDisplayOrientation(degrees);
+    }
+
+    public void setParameters(Camera.Parameters params)
+    {
+        try {
+            m_camera.setParameters(params);
+        } catch(Exception e) {
+            Log.d(TAG, e.getMessage());
+        }
+    }
+
+    public void setPreviewTexture(SurfaceTexture surfaceTexture)
+    {
+        try {
+            m_camera.setPreviewTexture(surfaceTexture);
+        } catch(Exception e) {
+            Log.d(TAG, e.getMessage());
+        }
+    }
+
+    public void startPreview()
+    {
+        m_camera.startPreview();
+    }
+
+    public void stopPreview()
+    {
+        m_camera.stopPreview();
+    }
+
+    public void autoFocus()
+    {
+        m_camera.autoFocus(this);
+    }
+
+    public void cancelAutoFocus()
+    {
+        m_camera.cancelAutoFocus();
+    }
+
+    public void takePicture()
+    {
+        try {
+            m_camera.takePicture(this, null, this);
+        } catch(Exception e) {
+            Log.d(TAG, e.getMessage());
+        }
+    }
+
+    @Override
+    public void onShutter()
+    {
+        notifyPictureExposed(m_cameraId);
+    }
+
+    @Override
+    public void onPictureTaken(byte[] data, Camera camera)
+    {
+        notifyPictureCaptured(m_cameraId, data);
+    }
+
+    @Override
+    public void onAutoFocus(boolean success, Camera camera)
+    {
+        notifyAutoFocusComplete(m_cameraId, success);
+    }
+
+    private static native void notifyAutoFocusComplete(int id, boolean success);
+    private static native void notifyPictureExposed(int id);
+    private static native void notifyPictureCaptured(int id, byte[] data);
+}
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtMediaRecorder.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtMediaRecorder.java
new file mode 100644
index 0000000000000000000000000000000000000000..d76cd2221bdfa5e17e547a54ace48a3d5ae5ccd2
--- /dev/null
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtMediaRecorder.java
@@ -0,0 +1,72 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtMultimedia module of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:LGPL$
+ ** Commercial License Usage
+ ** Licensees holding valid commercial Qt licenses may use this file in
+ ** accordance with the commercial license agreement provided with the
+ ** Software or, alternatively, in accordance with the terms contained in
+ ** a written agreement between you and Digia.  For licensing terms and
+ ** conditions see http://qt.digia.com/licensing.  For further information
+ ** use the contact form at http://qt.digia.com/contact-us.
+ **
+ ** GNU Lesser General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU Lesser
+ ** General Public License version 2.1 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.LGPL included in the
+ ** packaging of this file.  Please review the following information to
+ ** ensure the GNU Lesser General Public License version 2.1 requirements
+ ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ **
+ ** In addition, as a special exception, Digia gives you certain additional
+ ** rights.  These rights are described in the Digia Qt LGPL Exception
+ ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+ **
+ ** GNU General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU
+ ** General Public License version 3.0 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.GPL included in the
+ ** packaging of this file.  Please review the following information to
+ ** ensure the GNU General Public License version 3.0 requirements will be
+ ** met: http://www.gnu.org/copyleft/gpl.html.
+ **
+ **
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+package org.qtproject.qt5.android.multimedia;
+
+import android.media.MediaRecorder;
+
+public class QtMediaRecorder extends MediaRecorder implements MediaRecorder.OnErrorListener, MediaRecorder.OnInfoListener
+{
+    private long m_id = -1;
+
+    public QtMediaRecorder(long id)
+    {
+        super();
+        m_id = id;
+        setOnErrorListener(this);
+        setOnInfoListener(this);
+    }
+
+    @Override
+    public void onError(MediaRecorder mr, int what, int extra)
+    {
+        notifyError(m_id, what, extra);
+    }
+
+    @Override
+    public void onInfo(MediaRecorder mr, int what, int extra)
+    {
+        notifyInfo(m_id, what, extra);
+    }
+
+    private static native void notifyError(long id, int what, int extra);
+    private static native void notifyInfo(long id, int what, int extra);
+}
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtMultimediaUtils.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtMultimediaUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..69422d0f8a41415ebfe3f10d19d029324f8072c6
--- /dev/null
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtMultimediaUtils.java
@@ -0,0 +1,136 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtMultimedia module of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:LGPL$
+ ** Commercial License Usage
+ ** Licensees holding valid commercial Qt licenses may use this file in
+ ** accordance with the commercial license agreement provided with the
+ ** Software or, alternatively, in accordance with the terms contained in
+ ** a written agreement between you and Digia.  For licensing terms and
+ ** conditions see http://qt.digia.com/licensing.  For further information
+ ** use the contact form at http://qt.digia.com/contact-us.
+ **
+ ** GNU Lesser General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU Lesser
+ ** General Public License version 2.1 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.LGPL included in the
+ ** packaging of this file.  Please review the following information to
+ ** ensure the GNU Lesser General Public License version 2.1 requirements
+ ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ **
+ ** In addition, as a special exception, Digia gives you certain additional
+ ** rights.  These rights are described in the Digia Qt LGPL Exception
+ ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+ **
+ ** GNU General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU
+ ** General Public License version 3.0 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.GPL included in the
+ ** packaging of this file.  Please review the following information to
+ ** ensure the GNU General Public License version 3.0 requirements will be
+ ** met: http://www.gnu.org/copyleft/gpl.html.
+ **
+ **
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+package org.qtproject.qt5.android.multimedia;
+
+import android.content.Context;
+import android.app.Activity;
+import android.view.OrientationEventListener;
+import android.os.Environment;
+import android.media.MediaScannerConnection;
+import java.lang.String;
+import java.io.File;
+
+public class QtMultimediaUtils
+{
+    static private class OrientationListener extends OrientationEventListener
+    {
+        static public int deviceOrientation = 0;
+
+        public OrientationListener(Context context)
+        {
+            super(context);
+        }
+
+        @Override
+        public void onOrientationChanged(int orientation)
+        {
+            if (orientation == ORIENTATION_UNKNOWN)
+                return;
+
+            deviceOrientation = orientation;
+        }
+    }
+
+    static private Activity m_activity = null;
+    static private OrientationListener m_orientationListener = null;
+
+    static public void setActivity(Activity activity, Object activityDelegate)
+    {
+        m_activity = activity;
+        m_orientationListener = new OrientationListener(activity);
+    }
+
+    public QtMultimediaUtils()
+    {
+    }
+
+    static void enableOrientationListener(boolean enable)
+    {
+        if (enable)
+            m_orientationListener.enable();
+        else
+            m_orientationListener.disable();
+    }
+
+    static int getDeviceOrientation()
+    {
+        return m_orientationListener.deviceOrientation;
+    }
+
+    static String getDefaultMediaDirectory(int type)
+    {
+        String dirType = new String();
+        switch (type) {
+            case 0:
+                dirType = Environment.DIRECTORY_MUSIC;
+                break;
+            case 1:
+                dirType = Environment.DIRECTORY_MOVIES;
+                break;
+            case 2:
+                dirType = Environment.DIRECTORY_DCIM;
+                break;
+            default:
+                break;
+        }
+
+        File path = new File("");
+        if (type == 3) {
+            // There is no API for knowing the standard location for sounds
+            // such as voice recording. Though, it's typically in the 'Sounds'
+            // directory at the root of the external storage
+            path = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+                            + File.separator + "Sounds");
+        } else {
+            path = Environment.getExternalStoragePublicDirectory(dirType);
+        }
+
+        path.mkdirs(); // make sure the directory exists
+
+        return path.getAbsolutePath();
+    }
+
+    static void registerMediaFile(String file)
+    {
+        MediaScannerConnection.scanFile(m_activity, new String[] { file }, null, null);
+    }
+}
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTexture.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTexture.java
index b8837d5574382bb65ca571d403bc903b5d06dbd0..7632abd2daeac69d76b44f2f2b89aa2c4f55c577 100644
--- a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTexture.java
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTexture.java
@@ -43,28 +43,18 @@ package org.qtproject.qt5.android.multimedia;
 
 import android.graphics.SurfaceTexture;
 
-public class QtSurfaceTexture implements SurfaceTexture.OnFrameAvailableListener
+public class QtSurfaceTexture extends SurfaceTexture implements SurfaceTexture.OnFrameAvailableListener
 {
-    public SurfaceTexture surfaceTexture;
     private int texID;
 
     public QtSurfaceTexture(int texName)
     {
+        super(texName);
         texID = texName;
-        surfaceTexture = new SurfaceTexture(texName);
-        surfaceTexture.setOnFrameAvailableListener(this);
-    }
-
-    public void getTransformMatrix(float[] mtx)
-    {
-        surfaceTexture.getTransformMatrix(mtx);
-    }
-
-    public void updateTexImage()
-    {
-        surfaceTexture.updateTexImage();
+        setOnFrameAvailableListener(this);
     }
 
+    @Override
     public void onFrameAvailable(SurfaceTexture surfaceTexture)
     {
         notifyFrameAvailable(texID);
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder.java
index 15c5f231fc500d5e37712c74c4633a16bcffbe68..e676559d9d59bf8cdcb4b348dbe3f9b4fe882f92 100644
--- a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder.java
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder.java
@@ -55,59 +55,72 @@ public class QtSurfaceTextureHolder implements SurfaceHolder
         surfaceTexture = surface;
     }
 
+    @Override
     public void addCallback(SurfaceHolder.Callback callback)
     {
     }
 
+    @Override
     public Surface getSurface()
     {
         return surfaceTexture;
     }
 
+    @Override
     public Rect getSurfaceFrame()
     {
         return new Rect();
     }
 
+    @Override
     public boolean isCreating()
     {
         return false;
     }
 
+    @Override
     public Canvas lockCanvas(Rect dirty)
     {
         return new Canvas();
     }
 
+    @Override
     public Canvas lockCanvas()
     {
         return new Canvas();
     }
 
+    @Override
     public void removeCallback(SurfaceHolder.Callback callback)
     {
     }
 
+    @Override
     public void setFixedSize(int width, int height)
     {
     }
 
+    @Override
     public void setFormat(int format)
     {
     }
 
+    @Override
     public void setKeepScreenOn(boolean screenOn)
     {
     }
 
+    @Override
     public void setSizeFromLayout()
     {
     }
 
+    @Override
     public void setType(int type)
     {
     }
 
+    @Override
     public void unlockCanvasAndPost(Canvas canvas)
     {
     }
diff --git a/src/plugins/android/mediaplayer/mediaplayer.json b/src/plugins/android/mediaplayer/mediaplayer.json
deleted file mode 100644
index f371ebfd705774debd54b898923e4367cceb5e37..0000000000000000000000000000000000000000
--- a/src/plugins/android/mediaplayer/mediaplayer.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-    "Keys": ["androidmultimedia"],
-    "Services": ["org.qt-project.qt.mediaplayer"]
-}
diff --git a/src/plugins/android/mediaplayer/mediaplayer.pro b/src/plugins/android/mediaplayer/mediaplayer.pro
deleted file mode 100644
index cabe4c666aca3561d92aa506aa72491da26c450b..0000000000000000000000000000000000000000
--- a/src/plugins/android/mediaplayer/mediaplayer.pro
+++ /dev/null
@@ -1,24 +0,0 @@
-TARGET = androidmediaplayer
-QT += multimedia-private gui-private platformsupport-private network
-
-PLUGIN_TYPE = mediaservice
-PLUGIN_CLASS_NAME = QAndroidMediaPlayerServicePlugin
-load(qt_plugin)
-
-HEADERS += \
-    qandroidmediaplayercontrol.h \
-    qandroidmediaservice.h \
-    qandroidmetadatareadercontrol.h \
-    qandroidmediaserviceplugin.h \
-    qandroidvideorendercontrol.h \
-    qandroidvideooutput.h
-SOURCES += \
-    qandroidmediaplayercontrol.cpp \
-    qandroidmediaservice.cpp \
-    qandroidmetadatareadercontrol.cpp \
-    qandroidmediaserviceplugin.cpp \
-    qandroidvideorendercontrol.cpp
-
-OTHER_FILES += mediaplayer.json
-
-include (../wrappers/wrappers.pri)
diff --git a/src/plugins/android/src/android_mediaservice.json b/src/plugins/android/src/android_mediaservice.json
new file mode 100644
index 0000000000000000000000000000000000000000..a12be52bc6643afbf7a7b42720c6685362e69972
--- /dev/null
+++ b/src/plugins/android/src/android_mediaservice.json
@@ -0,0 +1,3 @@
+{
+    "Keys": ["org.qt-project.qt.camera", "org.qt-project.qt.mediaplayer", "org.qt-project.qt.audiosource"]
+}
diff --git a/src/plugins/android/src/common/common.pri b/src/plugins/android/src/common/common.pri
new file mode 100644
index 0000000000000000000000000000000000000000..f99dad507a03baa6b84c15ff05920bf832e64c79
--- /dev/null
+++ b/src/plugins/android/src/common/common.pri
@@ -0,0 +1,10 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+    $$PWD/qandroidvideooutput.h \
+    $$PWD/qandroidvideorendercontrol.h \
+    $$PWD/qandroidmultimediautils.h
+
+SOURCES += \
+    $$PWD/qandroidvideorendercontrol.cpp \
+    $$PWD/qandroidmultimediautils.cpp
diff --git a/src/plugins/android/src/common/qandroidmultimediautils.cpp b/src/plugins/android/src/common/qandroidmultimediautils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7ae40358f4e30039e34d45e20bada6a01da68547
--- /dev/null
+++ b/src/plugins/android/src/common/qandroidmultimediautils.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidmultimediautils.h"
+
+#include <qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+int qt_findClosestValue(const QList<int> &list, int value)
+{
+    if (list.size() < 2)
+        return 0;
+
+    int begin = 0;
+    int end = list.size() - 1;
+    int pivot = begin + (end - begin) / 2;
+    int v = list.at(pivot);
+
+    while (end - begin > 1) {
+        if (value == v)
+            return pivot;
+
+        if (value > v)
+            begin = pivot;
+        else
+            end = pivot;
+
+        pivot = begin + (end - begin) / 2;
+        v = list.at(pivot);
+    }
+
+    return value - v >= list.at(pivot + 1) - value ? pivot + 1 : pivot;
+}
+
+bool qt_sizeLessThan(const QSize &s1, const QSize &s2)
+{
+    return s1.width() * s1.height() < s2.width() * s2.height();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/common/qandroidmultimediautils.h b/src/plugins/android/src/common/qandroidmultimediautils.h
new file mode 100644
index 0000000000000000000000000000000000000000..1996209b01d0bf64908a2f89a45a7a85966b6292
--- /dev/null
+++ b/src/plugins/android/src/common/qandroidmultimediautils.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDMULTIMEDIAUTILS_H
+#define QANDROIDMULTIMEDIAUTILS_H
+
+#include <qglobal.h>
+#include <qsize.h>
+
+QT_BEGIN_NAMESPACE
+
+// return the index of the closest value to <value> in <list>
+// (binary search)
+int qt_findClosestValue(const QList<int> &list, int value);
+
+bool qt_sizeLessThan(const QSize &s1, const QSize &s2);
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDMULTIMEDIAUTILS_H
diff --git a/src/plugins/android/mediaplayer/qandroidvideooutput.h b/src/plugins/android/src/common/qandroidvideooutput.h
similarity index 97%
rename from src/plugins/android/mediaplayer/qandroidvideooutput.h
rename to src/plugins/android/src/common/qandroidvideooutput.h
index d59971f3b7c9c8415cc4fa2a675c5a4c2b6972a2..8110b67b07769cc9423be63b09848f8f8bf40960 100644
--- a/src/plugins/android/mediaplayer/qandroidvideooutput.h
+++ b/src/plugins/android/src/common/qandroidvideooutput.h
@@ -60,9 +60,12 @@ public:
 
     virtual bool isTextureReady() = 0;
     virtual void setTextureReadyCallback(TextureReadyCallback cb, void *context = 0) = 0;
+    virtual jobject surfaceTexture() = 0;
 
     virtual void setVideoSize(const QSize &size) = 0;
     virtual void stop() = 0;
+
+    virtual QImage toImage() = 0;
 };
 
 QT_END_NAMESPACE
diff --git a/src/plugins/android/mediaplayer/qandroidvideorendercontrol.cpp b/src/plugins/android/src/common/qandroidvideorendercontrol.cpp
similarity index 96%
rename from src/plugins/android/mediaplayer/qandroidvideorendercontrol.cpp
rename to src/plugins/android/src/common/qandroidvideorendercontrol.cpp
index fe26b455a6cded131bf429aac8ffc5763426bfb6..c5d38aebe66fcbd4a776ccbb53ea7ae87849fd7c 100644
--- a/src/plugins/android/mediaplayer/qandroidvideorendercontrol.cpp
+++ b/src/plugins/android/src/common/qandroidvideorendercontrol.cpp
@@ -146,9 +146,7 @@ QAndroidVideoRendererControl::~QAndroidVideoRendererControl()
         m_glContext->makeCurrent(m_offscreenSurface);
 
     if (m_surfaceTexture) {
-        QJNILocalRef<jobject> surfaceTex = m_surfaceTexture->surfaceTexture();
-        QJNIObject obj(surfaceTex.object());
-        obj.callMethod<void>("release");
+        m_surfaceTexture->callMethod<void>("release");
         delete m_surfaceTexture;
         m_surfaceTexture = 0;
     }
@@ -270,11 +268,9 @@ jobject QAndroidVideoRendererControl::surfaceHolder()
         return 0;
 
     if (!m_surfaceHolder) {
-        QJNILocalRef<jobject> surfaceTex = m_surfaceTexture->surfaceTexture();
-
         m_androidSurface = new QJNIObject("android/view/Surface",
                                           "(Landroid/graphics/SurfaceTexture;)V",
-                                          surfaceTex.object());
+                                          m_surfaceTexture->object());
 
         m_surfaceHolder = new JSurfaceTextureHolder(m_androidSurface->object());
     }
@@ -282,11 +278,21 @@ jobject QAndroidVideoRendererControl::surfaceHolder()
     return m_surfaceHolder->object();
 }
 
+jobject QAndroidVideoRendererControl::surfaceTexture()
+{
+    if (!initSurfaceTexture())
+        return 0;
+
+    return m_surfaceTexture->object();
+}
+
 void QAndroidVideoRendererControl::setVideoSize(const QSize &size)
 {
     if (m_nativeSize == size)
         return;
 
+    stop();
+
     m_nativeSize = size;
 
     delete m_fbo;
@@ -300,6 +306,14 @@ void QAndroidVideoRendererControl::stop()
     m_nativeSize = QSize();
 }
 
+QImage QAndroidVideoRendererControl::toImage()
+{
+    if (!m_fbo)
+        return QImage();
+
+    return m_fbo->toImage().mirrored();
+}
+
 void QAndroidVideoRendererControl::onFrameAvailable()
 {
     if (m_glContext)
diff --git a/src/plugins/android/mediaplayer/qandroidvideorendercontrol.h b/src/plugins/android/src/common/qandroidvideorendercontrol.h
similarity index 97%
rename from src/plugins/android/mediaplayer/qandroidvideorendercontrol.h
rename to src/plugins/android/src/common/qandroidvideorendercontrol.h
index cd935502c5bbb11d020cb8ebccbb920ed9624d76..d8078f075dc48879cf95c6343120fcb79b38d905 100644
--- a/src/plugins/android/mediaplayer/qandroidvideorendercontrol.h
+++ b/src/plugins/android/src/common/qandroidvideorendercontrol.h
@@ -67,8 +67,10 @@ public:
     jobject surfaceHolder() Q_DECL_OVERRIDE;
     bool isTextureReady() Q_DECL_OVERRIDE;
     void setTextureReadyCallback(TextureReadyCallback cb, void *context = 0) Q_DECL_OVERRIDE;
+    jobject surfaceTexture() Q_DECL_OVERRIDE;
     void setVideoSize(const QSize &size) Q_DECL_OVERRIDE;
     void stop() Q_DECL_OVERRIDE;
+    QImage toImage() Q_DECL_OVERRIDE;
 
     bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE;
 
diff --git a/src/plugins/android/src/mediacapture/mediacapture.pri b/src/plugins/android/src/mediacapture/mediacapture.pri
new file mode 100644
index 0000000000000000000000000000000000000000..d994bebfd4f8a13ec53846272650437cd1517db4
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/mediacapture.pri
@@ -0,0 +1,47 @@
+INCLUDEPATH += $$PWD
+
+SOURCES += \
+    $$PWD/qandroidcaptureservice.cpp \
+    $$PWD/qandroidcameracontrol.cpp \
+    $$PWD/qandroidvideodeviceselectorcontrol.cpp \
+    $$PWD/qandroidcamerasession.cpp \
+    $$PWD/qandroidcamerazoomcontrol.cpp \
+    $$PWD/qandroidcameraexposurecontrol.cpp \
+    $$PWD/qandroidcameraimageprocessingcontrol.cpp \
+    $$PWD/qandroidimageencodercontrol.cpp \
+    $$PWD/qandroidcameraimagecapturecontrol.cpp \
+    $$PWD/qandroidcameracapturedestinationcontrol.cpp \
+    $$PWD/qandroidcameracapturebufferformatcontrol.cpp \
+    $$PWD/qandroidmediastoragelocation.cpp \
+    $$PWD/qandroidcameraflashcontrol.cpp \
+    $$PWD/qandroidcamerafocuscontrol.cpp \
+    $$PWD/qandroidcameralockscontrol.cpp \
+    $$PWD/qandroidcapturesession.cpp \
+    $$PWD/qandroidmediarecordercontrol.cpp \
+    $$PWD/qandroidaudioencodersettingscontrol.cpp \
+    $$PWD/qandroidmediacontainercontrol.cpp \
+    $$PWD/qandroidvideoencodersettingscontrol.cpp \
+    $$PWD/qandroidaudioinputselectorcontrol.cpp
+
+HEADERS += \
+    $$PWD/qandroidcaptureservice.h \
+    $$PWD/qandroidcameracontrol.h \
+    $$PWD/qandroidvideodeviceselectorcontrol.h \
+    $$PWD/qandroidcamerasession.h \
+    $$PWD/qandroidcamerazoomcontrol.h \
+    $$PWD/qandroidcameraexposurecontrol.h \
+    $$PWD/qandroidcameraimageprocessingcontrol.h \
+    $$PWD/qandroidimageencodercontrol.h \
+    $$PWD/qandroidcameraimagecapturecontrol.h \
+    $$PWD/qandroidcameracapturedestinationcontrol.h \
+    $$PWD/qandroidcameracapturebufferformatcontrol.h \
+    $$PWD/qandroidmediastoragelocation.h \
+    $$PWD/qandroidcameraflashcontrol.h \
+    $$PWD/qandroidcamerafocuscontrol.h \
+    $$PWD/qandroidcameralockscontrol.h \
+    $$PWD/qandroidcapturesession.h \
+    $$PWD/qandroidmediarecordercontrol.h \
+    $$PWD/qandroidaudioencodersettingscontrol.h \
+    $$PWD/qandroidmediacontainercontrol.h \
+    $$PWD/qandroidvideoencodersettingscontrol.h \
+    $$PWD/qandroidaudioinputselectorcontrol.h
diff --git a/src/plugins/android/src/mediacapture/qandroidaudioencodersettingscontrol.cpp b/src/plugins/android/src/mediacapture/qandroidaudioencodersettingscontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8015ec38c88acfecf314fe14fe5f8711b656a6fb
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidaudioencodersettingscontrol.cpp
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidaudioencodersettingscontrol.h"
+
+#include "qandroidcapturesession.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidAudioEncoderSettingsControl::QAndroidAudioEncoderSettingsControl(QAndroidCaptureSession *session)
+    : QAudioEncoderSettingsControl()
+    , m_session(session)
+{
+}
+
+QStringList QAndroidAudioEncoderSettingsControl::supportedAudioCodecs() const
+{
+    return QStringList() << QLatin1String("amr-nb") << QLatin1String("amr-wb") << QLatin1String("aac");
+}
+
+QString QAndroidAudioEncoderSettingsControl::codecDescription(const QString &codecName) const
+{
+    if (codecName == QLatin1String("amr-nb"))
+        return tr("Adaptive Multi-Rate Narrowband (AMR-NB) audio codec");
+    else if (codecName == QLatin1String("amr-wb"))
+        return tr("Adaptive Multi-Rate Wideband (AMR-WB) audio codec");
+    else if (codecName == QLatin1String("aac"))
+        return tr("AAC Low Complexity (AAC-LC) audio codec");
+
+    return QString();
+}
+
+QList<int> QAndroidAudioEncoderSettingsControl::supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous) const
+{
+    if (continuous)
+        *continuous = false;
+
+    if (settings.isNull() || settings.codec().isNull() || settings.codec() == QLatin1String("aac")) {
+        return QList<int>() << 8000 << 11025 << 12000 << 16000 << 22050
+                            << 24000 << 32000 << 44100 << 48000 << 96000;
+    } else if (settings.codec() == QLatin1String("amr-nb")) {
+        return QList<int>() << 8000;
+    } else if (settings.codec() == QLatin1String("amr-wb")) {
+        return QList<int>() << 16000;
+    }
+
+    return QList<int>();
+}
+
+QAudioEncoderSettings QAndroidAudioEncoderSettingsControl::audioSettings() const
+{
+    return m_session->audioSettings();
+}
+
+void QAndroidAudioEncoderSettingsControl::setAudioSettings(const QAudioEncoderSettings &settings)
+{
+    m_session->setAudioSettings(settings);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidaudioencodersettingscontrol.h b/src/plugins/android/src/mediacapture/qandroidaudioencodersettingscontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..11a35fe6aaf98ab0920e5ff5f57b44b78b67c06a
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidaudioencodersettingscontrol.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDAUDIOENCODERSETTINGSCONTROL_H
+#define QANDROIDAUDIOENCODERSETTINGSCONTROL_H
+
+#include <qaudioencodersettingscontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCaptureSession;
+
+class QAndroidAudioEncoderSettingsControl : public QAudioEncoderSettingsControl
+{
+    Q_OBJECT
+public:
+    explicit QAndroidAudioEncoderSettingsControl(QAndroidCaptureSession *session);
+
+    QStringList supportedAudioCodecs() const Q_DECL_OVERRIDE;
+    QString codecDescription(const QString &codecName) const Q_DECL_OVERRIDE;
+    QList<int> supportedSampleRates(const QAudioEncoderSettings &settings, bool *continuous = 0) const Q_DECL_OVERRIDE;
+    QAudioEncoderSettings audioSettings() const Q_DECL_OVERRIDE;
+    void setAudioSettings(const QAudioEncoderSettings &settings) Q_DECL_OVERRIDE;
+
+private:
+    QAndroidCaptureSession *m_session;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDAUDIOENCODERSETTINGSCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidaudioinputselectorcontrol.cpp b/src/plugins/android/src/mediacapture/qandroidaudioinputselectorcontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4032b2d0bb9e06e79c30524867842797d2e06acd
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidaudioinputselectorcontrol.cpp
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidaudioinputselectorcontrol.h"
+
+#include "qandroidcapturesession.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidAudioInputSelectorControl::QAndroidAudioInputSelectorControl(QAndroidCaptureSession *session)
+    : QAudioInputSelectorControl()
+    , m_session(session)
+{
+    connect(m_session, SIGNAL(audioInputChanged(QString)), this, SIGNAL(activeInputChanged(QString)));
+}
+
+QList<QString> QAndroidAudioInputSelectorControl::availableInputs() const
+{
+    return QList<QString>() << QLatin1String("default")
+                            << QLatin1String("mic")
+                            << QLatin1String("voice_uplink")
+                            << QLatin1String("voice_downlink")
+                            << QLatin1String("voice_call")
+                            << QLatin1String("voice_recognition");
+}
+
+QString QAndroidAudioInputSelectorControl::inputDescription(const QString& name) const
+{
+    return availableDeviceDescription(name.toLatin1());
+}
+
+QString QAndroidAudioInputSelectorControl::defaultInput() const
+{
+    return QLatin1String("default");
+}
+
+QString QAndroidAudioInputSelectorControl::activeInput() const
+{
+    return m_session->audioInput();
+}
+
+void QAndroidAudioInputSelectorControl::setActiveInput(const QString& name)
+{
+    m_session->setAudioInput(name);
+}
+
+QList<QByteArray> QAndroidAudioInputSelectorControl::availableDevices()
+{
+    return QList<QByteArray>() << "default"
+                               << "mic"
+                               << "voice_uplink"
+                               << "voice_downlink"
+                               << "voice_call"
+                               << "voice_recognition";
+}
+
+QString QAndroidAudioInputSelectorControl::availableDeviceDescription(const QByteArray &device)
+{
+    if (device == "default")
+        return QLatin1String("Default audio source");
+    else if (device == "mic")
+        return QLatin1String("Microphone audio source");
+    else if (device == "voice_uplink")
+        return QLatin1String("Voice call uplink (Tx) audio source");
+    else if (device == "voice_downlink")
+        return QLatin1String("Voice call downlink (Rx) audio source");
+    else if (device == "voice_call")
+        return QLatin1String("Voice call uplink + downlink audio source");
+    else if (device == "voice_recognition")
+        return QLatin1String("Microphone audio source tuned for voice recognition");
+    else
+        return QString();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidaudioinputselectorcontrol.h b/src/plugins/android/src/mediacapture/qandroidaudioinputselectorcontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..3dfa7c712d351e332f3823c91ab9976e8b3a5871
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidaudioinputselectorcontrol.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDAUDIOINPUTSELECTORCONTROL_H
+#define QANDROIDAUDIOINPUTSELECTORCONTROL_H
+
+#include <qaudioinputselectorcontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCaptureSession;
+
+class QAndroidAudioInputSelectorControl : public QAudioInputSelectorControl
+{
+    Q_OBJECT
+public:
+    explicit QAndroidAudioInputSelectorControl(QAndroidCaptureSession *session);
+
+    QList<QString> availableInputs() const;
+    QString inputDescription(const QString& name) const;
+    QString defaultInput() const;
+
+    QString activeInput() const;
+    void setActiveInput(const QString& name);
+
+    static QList<QByteArray> availableDevices();
+    static QString availableDeviceDescription(const QByteArray &device);
+
+private:
+    QAndroidCaptureSession *m_session;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDAUDIOINPUTSELECTORCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidcameracapturebufferformatcontrol.cpp b/src/plugins/android/src/mediacapture/qandroidcameracapturebufferformatcontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dc7f20ee7331b7102fc11775d668561d600c77d2
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameracapturebufferformatcontrol.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidcameracapturebufferformatcontrol.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidCameraCaptureBufferFormatControl::QAndroidCameraCaptureBufferFormatControl()
+    : QCameraCaptureBufferFormatControl()
+{
+}
+
+QList<QVideoFrame::PixelFormat> QAndroidCameraCaptureBufferFormatControl::supportedBufferFormats() const
+{
+    return (QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_Jpeg);
+}
+
+QVideoFrame::PixelFormat QAndroidCameraCaptureBufferFormatControl::bufferFormat() const
+{
+    return QVideoFrame::Format_Jpeg;
+}
+
+void QAndroidCameraCaptureBufferFormatControl::setBufferFormat(QVideoFrame::PixelFormat format)
+{
+    Q_UNUSED(format)
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcameracapturebufferformatcontrol.h b/src/plugins/android/src/mediacapture/qandroidcameracapturebufferformatcontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..cf8bd4933b60245f0533fc9aaffc03b8b75fe59a
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameracapturebufferformatcontrol.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDCAMERACAPTUREBUFFERFORMATCONTROL_H
+#define QANDROIDCAMERACAPTUREBUFFERFORMATCONTROL_H
+
+#include <qcameracapturebufferformatcontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraCaptureBufferFormatControl : public QCameraCaptureBufferFormatControl
+{
+    Q_OBJECT
+public:
+    QAndroidCameraCaptureBufferFormatControl();
+
+    QList<QVideoFrame::PixelFormat> supportedBufferFormats() const Q_DECL_OVERRIDE;
+    QVideoFrame::PixelFormat bufferFormat() const Q_DECL_OVERRIDE;
+    void setBufferFormat(QVideoFrame::PixelFormat format) Q_DECL_OVERRIDE;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDCAMERACAPTUREBUFFERFORMATCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidcameracapturedestinationcontrol.cpp b/src/plugins/android/src/mediacapture/qandroidcameracapturedestinationcontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..870a4240ddad122fb325afa5b0fe37d23f250956
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameracapturedestinationcontrol.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidcameracapturedestinationcontrol.h"
+
+#include "qandroidcamerasession.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidCameraCaptureDestinationControl::QAndroidCameraCaptureDestinationControl(QAndroidCameraSession *session)
+    : QCameraCaptureDestinationControl()
+    , m_session(session)
+{
+    connect(m_session, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations)),
+            this, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations)));
+}
+
+bool QAndroidCameraCaptureDestinationControl::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const
+{
+    return m_session->isCaptureDestinationSupported(destination);
+}
+
+QCameraImageCapture::CaptureDestinations QAndroidCameraCaptureDestinationControl::captureDestination() const
+{
+    return m_session->captureDestination();;
+}
+
+void QAndroidCameraCaptureDestinationControl::setCaptureDestination(QCameraImageCapture::CaptureDestinations destination)
+{
+    m_session->setCaptureDestination(destination);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcameracapturedestinationcontrol.h b/src/plugins/android/src/mediacapture/qandroidcameracapturedestinationcontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..46ff96bcaa2bfe7163088fbeee2443bab31c7154
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameracapturedestinationcontrol.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDCAMERACAPTUREDESTINATIONCONTROL_H
+#define QANDROIDCAMERACAPTUREDESTINATIONCONTROL_H
+
+#include <qcameracapturedestinationcontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraSession;
+
+class QAndroidCameraCaptureDestinationControl : public QCameraCaptureDestinationControl
+{
+    Q_OBJECT
+public:
+    explicit QAndroidCameraCaptureDestinationControl(QAndroidCameraSession *session);
+
+    bool isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const Q_DECL_OVERRIDE;
+    QCameraImageCapture::CaptureDestinations captureDestination() const Q_DECL_OVERRIDE;
+    void setCaptureDestination(QCameraImageCapture::CaptureDestinations destination) Q_DECL_OVERRIDE;
+
+private:
+    QAndroidCameraSession *m_session;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDCAMERACAPTUREDESTINATIONCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidcameracontrol.cpp b/src/plugins/android/src/mediacapture/qandroidcameracontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f91ae1e8986126b0ba1773cdf1dc75806c952f4f
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameracontrol.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidcameracontrol.h"
+
+#include "qandroidcamerasession.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidCameraControl::QAndroidCameraControl(QAndroidCameraSession *session)
+    : QCameraControl(0)
+    , m_cameraSession(session)
+
+{
+    connect(m_cameraSession, SIGNAL(statusChanged(QCamera::Status)),
+            this, SIGNAL(statusChanged(QCamera::Status)));
+
+    connect(m_cameraSession, SIGNAL(stateChanged(QCamera::State)),
+            this, SIGNAL(stateChanged(QCamera::State)));
+
+    connect(m_cameraSession, SIGNAL(error(int,QString)), this, SIGNAL(error(int,QString)));
+
+    connect(m_cameraSession, SIGNAL(captureModeChanged(QCamera::CaptureModes)),
+            this, SIGNAL(captureModeChanged(QCamera::CaptureModes)));
+}
+
+QAndroidCameraControl::~QAndroidCameraControl()
+{
+}
+
+QCamera::CaptureModes QAndroidCameraControl::captureMode() const
+{
+    return m_cameraSession->captureMode();
+}
+
+void QAndroidCameraControl::setCaptureMode(QCamera::CaptureModes mode)
+{
+    m_cameraSession->setCaptureMode(mode);
+}
+
+bool QAndroidCameraControl::isCaptureModeSupported(QCamera::CaptureModes mode) const
+{
+    return m_cameraSession->isCaptureModeSupported(mode);
+}
+
+void QAndroidCameraControl::setState(QCamera::State state)
+{
+    m_cameraSession->setState(state);
+}
+
+QCamera::State QAndroidCameraControl::state() const
+{
+    return m_cameraSession->state();
+}
+
+QCamera::Status QAndroidCameraControl::status() const
+{
+    return m_cameraSession->status();
+}
+
+bool QAndroidCameraControl::canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const
+{
+    Q_UNUSED(status);
+
+    switch (changeType) {
+    case QCameraControl::CaptureMode:
+    case QCameraControl::ImageEncodingSettings:
+    case QCameraControl::VideoEncodingSettings:
+    case QCameraControl::Viewfinder:
+        return true;
+    default:
+        return false;
+    }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcameracontrol.h b/src/plugins/android/src/mediacapture/qandroidcameracontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..f5070c13e8bc2e6918172f3f0d30450ca51ec1ec
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameracontrol.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QANDROIDCAMERACONTROL_H
+#define QANDROIDCAMERACONTROL_H
+
+#include <qcameracontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraSession;
+
+class QAndroidCameraControl : public QCameraControl
+{
+    Q_OBJECT
+public:
+    explicit QAndroidCameraControl(QAndroidCameraSession *session);
+    virtual ~QAndroidCameraControl();
+
+    QCamera::State state() const;
+    void setState(QCamera::State state);
+
+    QCamera::Status status() const;
+
+    QCamera::CaptureModes captureMode() const;
+    void setCaptureMode(QCamera::CaptureModes mode);
+    bool isCaptureModeSupported(QCamera::CaptureModes mode) const;
+
+    bool canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const;
+
+private:
+    QAndroidCameraSession *m_cameraSession;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDCAMERACONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidcameraexposurecontrol.cpp b/src/plugins/android/src/mediacapture/qandroidcameraexposurecontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..03bbadb938c5c877be5a48ced759255ff77f3930
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameraexposurecontrol.cpp
@@ -0,0 +1,227 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidcameraexposurecontrol.h"
+
+#include "qandroidcamerasession.h"
+#include "jcamera.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidCameraExposureControl::QAndroidCameraExposureControl(QAndroidCameraSession *session)
+    : QCameraExposureControl()
+    , m_session(session)
+    , m_minExposureCompensationIndex(0)
+    , m_maxExposureCompensationIndex(0)
+    , m_exposureCompensationStep(0.0)
+    , m_requestedExposureCompensation(0.0)
+    , m_actualExposureCompensation(0.0)
+    , m_requestedExposureMode(QCameraExposure::ExposureAuto)
+    , m_actualExposureMode(QCameraExposure::ExposureAuto)
+{
+    connect(m_session, SIGNAL(opened()),
+            this, SLOT(onCameraOpened()));
+}
+
+bool QAndroidCameraExposureControl::isParameterSupported(ExposureParameter parameter) const
+{
+    switch (parameter) {
+    case QCameraExposureControl::ISO:
+        return false;
+    case QCameraExposureControl::Aperture:
+        return false;
+    case QCameraExposureControl::ShutterSpeed:
+        return false;
+    case QCameraExposureControl::ExposureCompensation:
+        return true;
+    case QCameraExposureControl::FlashPower:
+        return false;
+    case QCameraExposureControl::FlashCompensation:
+        return false;
+    case QCameraExposureControl::TorchPower:
+        return false;
+    case QCameraExposureControl::SpotMeteringPoint:
+        return false;
+    case QCameraExposureControl::ExposureMode:
+        return true;
+    case QCameraExposureControl::MeteringMode:
+        return false;
+    default:
+        return false;
+    }
+}
+
+QVariantList QAndroidCameraExposureControl::supportedParameterRange(ExposureParameter parameter, bool *continuous) const
+{
+    if (!m_session->camera())
+        return QVariantList();
+
+    if (continuous)
+        *continuous = false;
+
+    if (parameter == QCameraExposureControl::ExposureCompensation)
+        return m_supportedExposureCompensations;
+    else if (parameter == QCameraExposureControl::ExposureMode)
+        return m_supportedExposureModes;
+
+    return QVariantList();
+}
+
+QVariant QAndroidCameraExposureControl::requestedValue(ExposureParameter parameter) const
+{
+    if (parameter == QCameraExposureControl::ExposureCompensation)
+        return QVariant::fromValue(m_requestedExposureCompensation);
+    else if (parameter == QCameraExposureControl::ExposureMode)
+        return QVariant::fromValue(m_requestedExposureMode);
+
+    return QVariant();
+}
+
+QVariant QAndroidCameraExposureControl::actualValue(ExposureParameter parameter) const
+{
+    if (parameter == QCameraExposureControl::ExposureCompensation)
+        return QVariant::fromValue(m_actualExposureCompensation);
+    else if (parameter == QCameraExposureControl::ExposureMode)
+        return QVariant::fromValue(m_actualExposureMode);
+
+    return QVariant();
+}
+
+bool QAndroidCameraExposureControl::setValue(ExposureParameter parameter, const QVariant& value)
+{
+    if (!m_session->camera() || !value.isValid())
+        return false;
+
+    if (parameter == QCameraExposureControl::ExposureCompensation) {
+        m_requestedExposureCompensation = value.toReal();
+        emit requestedValueChanged(QCameraExposureControl::ExposureCompensation);
+
+        int expCompIndex = qRound(m_requestedExposureCompensation / m_exposureCompensationStep);
+        if (expCompIndex >= m_minExposureCompensationIndex
+                && expCompIndex <= m_maxExposureCompensationIndex) {
+            m_session->camera()->setExposureCompensation(expCompIndex);
+
+            m_actualExposureCompensation = expCompIndex * m_exposureCompensationStep;
+            emit actualValueChanged(QCameraExposureControl::ExposureCompensation);
+
+            return true;
+        }
+
+    } else if (parameter == QCameraExposureControl::ExposureMode) {
+        m_requestedExposureMode = value.value<QCameraExposure::ExposureMode>();
+        emit requestedValueChanged(QCameraExposureControl::ExposureMode);
+
+        if (!m_supportedExposureModes.isEmpty()) {
+            m_actualExposureMode = m_requestedExposureMode;
+
+            QString sceneMode;
+            switch (m_requestedExposureMode) {
+            case QCameraExposure::ExposureAuto:
+                sceneMode = QLatin1String("auto");
+                break;
+            case QCameraExposure::ExposureSports:
+                sceneMode = QLatin1String("sports");
+                break;
+            case QCameraExposure::ExposurePortrait:
+                sceneMode = QLatin1String("portrait");
+                break;
+            case QCameraExposure::ExposureBeach:
+                sceneMode = QLatin1String("beach");
+                break;
+            case QCameraExposure::ExposureSnow:
+                sceneMode = QLatin1String("snow");
+                break;
+            case QCameraExposure::ExposureNight:
+                sceneMode = QLatin1String("night");
+                break;
+            default:
+                sceneMode = QLatin1String("auto");
+                m_actualExposureMode = QCameraExposure::ExposureAuto;
+                break;
+            }
+
+            m_session->camera()->setSceneMode(sceneMode);
+            emit actualValueChanged(QCameraExposureControl::ExposureMode);
+
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void QAndroidCameraExposureControl::onCameraOpened()
+{
+    m_requestedExposureCompensation = m_actualExposureCompensation = 0.0;
+    m_requestedExposureMode = m_actualExposureMode = QCameraExposure::ExposureAuto;
+    emit requestedValueChanged(QCameraExposureControl::ExposureCompensation);
+    emit actualValueChanged(QCameraExposureControl::ExposureCompensation);
+    emit requestedValueChanged(QCameraExposureControl::ExposureMode);
+    emit actualValueChanged(QCameraExposureControl::ExposureMode);
+
+    m_minExposureCompensationIndex = m_session->camera()->getMinExposureCompensation();
+    m_maxExposureCompensationIndex = m_session->camera()->getMaxExposureCompensation();
+    m_exposureCompensationStep = m_session->camera()->getExposureCompensationStep();
+    for (int i = m_minExposureCompensationIndex; i <= m_maxExposureCompensationIndex; ++i)
+        m_supportedExposureCompensations.append(i * m_exposureCompensationStep);
+    emit parameterRangeChanged(QCameraExposureControl::ExposureCompensation);
+
+    m_supportedExposureModes.clear();
+    QStringList sceneModes = m_session->camera()->getSupportedSceneModes();
+    for (int i = 0; i < sceneModes.size(); ++i) {
+        const QString &sceneMode = sceneModes.at(i);
+        if (sceneMode == QLatin1String("auto"))
+            m_supportedExposureModes << QVariant::fromValue(QCameraExposure::ExposureAuto);
+        else if (sceneMode == QLatin1String("beach"))
+            m_supportedExposureModes << QVariant::fromValue(QCameraExposure::ExposureBeach);
+        else if (sceneMode == QLatin1String("night"))
+            m_supportedExposureModes << QVariant::fromValue(QCameraExposure::ExposureNight);
+        else if (sceneMode == QLatin1String("portrait"))
+            m_supportedExposureModes << QVariant::fromValue(QCameraExposure::ExposurePortrait);
+        else if (sceneMode == QLatin1String("snow"))
+            m_supportedExposureModes << QVariant::fromValue(QCameraExposure::ExposureSnow);
+        else if (sceneMode == QLatin1String("sports"))
+            m_supportedExposureModes << QVariant::fromValue(QCameraExposure::ExposureSports);
+    }
+    emit parameterRangeChanged(QCameraExposureControl::ExposureMode);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcameraexposurecontrol.h b/src/plugins/android/src/mediacapture/qandroidcameraexposurecontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..d07fea5394c7b50e0a027ef6c887adab4a5e3a15
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameraexposurecontrol.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDCAMERAEXPOSURECONTROL_H
+#define QANDROIDCAMERAEXPOSURECONTROL_H
+
+#include <qcameraexposurecontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraSession;
+
+class QAndroidCameraExposureControl : public QCameraExposureControl
+{
+    Q_OBJECT
+public:
+    explicit QAndroidCameraExposureControl(QAndroidCameraSession *session);
+
+    bool isParameterSupported(ExposureParameter parameter) const Q_DECL_OVERRIDE;
+    QVariantList supportedParameterRange(ExposureParameter parameter, bool *continuous) const Q_DECL_OVERRIDE;
+
+    QVariant requestedValue(ExposureParameter parameter) const Q_DECL_OVERRIDE;
+    QVariant actualValue(ExposureParameter parameter) const Q_DECL_OVERRIDE;
+    bool setValue(ExposureParameter parameter, const QVariant& value) Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+    void onCameraOpened();
+
+private:
+    QAndroidCameraSession *m_session;
+
+    QVariantList m_supportedExposureCompensations;
+    QVariantList m_supportedExposureModes;
+
+    int m_minExposureCompensationIndex;
+    int m_maxExposureCompensationIndex;
+    qreal m_exposureCompensationStep;
+
+    qreal m_requestedExposureCompensation;
+    qreal m_actualExposureCompensation;
+    QCameraExposure::ExposureMode m_requestedExposureMode;
+    QCameraExposure::ExposureMode m_actualExposureMode;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDCAMERAEXPOSURECONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidcameraflashcontrol.cpp b/src/plugins/android/src/mediacapture/qandroidcameraflashcontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..253b1baa56997fc4fe3f32c5151cb55588a2d6f5
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameraflashcontrol.cpp
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidcameraflashcontrol.h"
+
+#include "qandroidcamerasession.h"
+#include "jcamera.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidCameraFlashControl::QAndroidCameraFlashControl(QAndroidCameraSession *session)
+    : QCameraFlashControl()
+    , m_session(session)
+    , m_flashMode(QCameraExposure::FlashOff)
+{
+    connect(m_session, SIGNAL(opened()),
+            this, SLOT(onCameraOpened()));
+}
+
+QCameraExposure::FlashModes QAndroidCameraFlashControl::flashMode() const
+{
+    return m_flashMode;
+}
+
+void QAndroidCameraFlashControl::setFlashMode(QCameraExposure::FlashModes mode)
+{
+    if (m_flashMode == mode || !m_session->camera() || !isFlashModeSupported(mode))
+        return;
+
+    // if torch was enabled, it first needs to be turned off before setting another mode
+    if (m_flashMode == QCameraExposure::FlashVideoLight)
+        m_session->camera()->setFlashMode(QLatin1String("off"));
+
+    m_flashMode = mode;
+
+    QString flashMode;
+    if (mode.testFlag(QCameraExposure::FlashAuto))
+        flashMode = QLatin1String("auto");
+    else if (mode.testFlag(QCameraExposure::FlashOn))
+        flashMode = QLatin1String("on");
+    else if (mode.testFlag(QCameraExposure::FlashRedEyeReduction))
+        flashMode = QLatin1String("red-eye");
+    else if (mode.testFlag(QCameraExposure::FlashVideoLight))
+        flashMode = QLatin1String("torch");
+    else // FlashOff
+        flashMode = QLatin1String("off");
+
+    m_session->camera()->setFlashMode(flashMode);
+}
+
+bool QAndroidCameraFlashControl::isFlashModeSupported(QCameraExposure::FlashModes mode) const
+{
+    return m_supportedFlashModes.contains(mode);
+}
+
+bool QAndroidCameraFlashControl::isFlashReady() const
+{
+    // Android doesn't have an API for that
+    return true;
+}
+
+void QAndroidCameraFlashControl::onCameraOpened()
+{
+    m_supportedFlashModes.clear();
+
+    QStringList flashModes = m_session->camera()->getSupportedFlashModes();
+    for (int i = 0; i < flashModes.size(); ++i) {
+        const QString &flashMode = flashModes.at(i);
+        if (flashMode == QLatin1String("off"))
+            m_supportedFlashModes << QCameraExposure::FlashOff;
+        else if (flashMode == QLatin1String("auto"))
+            m_supportedFlashModes << QCameraExposure::FlashAuto;
+        else if (flashMode == QLatin1String("on"))
+            m_supportedFlashModes << QCameraExposure::FlashOn;
+        else if (flashMode == QLatin1String("red-eye"))
+            m_supportedFlashModes << QCameraExposure::FlashRedEyeReduction;
+        else if (flashMode == QLatin1String("torch"))
+            m_supportedFlashModes << QCameraExposure::FlashVideoLight;
+    }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcameraflashcontrol.h b/src/plugins/android/src/mediacapture/qandroidcameraflashcontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..35ed718947226ad331f45655e474bd720b9abf51
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameraflashcontrol.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDCAMERAFLASHCONTROL_H
+#define QANDROIDCAMERAFLASHCONTROL_H
+
+#include <qcameraflashcontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraSession;
+
+class QAndroidCameraFlashControl : public QCameraFlashControl
+{
+    Q_OBJECT
+public:
+    explicit QAndroidCameraFlashControl(QAndroidCameraSession *session);
+
+    QCameraExposure::FlashModes flashMode() const Q_DECL_OVERRIDE;
+    void setFlashMode(QCameraExposure::FlashModes mode) Q_DECL_OVERRIDE;
+    bool isFlashModeSupported(QCameraExposure::FlashModes mode) const Q_DECL_OVERRIDE;
+    bool isFlashReady() const Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+    void onCameraOpened();
+
+private:
+    QAndroidCameraSession *m_session;
+    QList<QCameraExposure::FlashModes> m_supportedFlashModes;
+    QCameraExposure::FlashModes m_flashMode;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDCAMERAFLASHCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerafocuscontrol.cpp b/src/plugins/android/src/mediacapture/qandroidcamerafocuscontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cb785fe1e787605814b6fb76ee912c7f21b69887
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcamerafocuscontrol.cpp
@@ -0,0 +1,304 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidcamerafocuscontrol.h"
+
+#include "qandroidcamerasession.h"
+#include "jcamera.h"
+
+QT_BEGIN_NAMESPACE
+
+static QRect adjustedArea(const QRectF &area)
+{
+    // Qt maps focus points in the range (0.0, 0.0) -> (1.0, 1.0)
+    // Android maps focus points in the range (-1000, -1000) -> (1000, 1000)
+    // Converts an area in Qt coordinates to Android coordinates
+    return QRect(-1000 + qRound(area.x() * 2000),
+                 -1000 + qRound(area.y() * 2000),
+                 qRound(area.width() * 2000),
+                 qRound(area.height() * 2000))
+            .intersected(QRect(-1000, -1000, 2000, 2000));
+}
+
+QAndroidCameraFocusControl::QAndroidCameraFocusControl(QAndroidCameraSession *session)
+    : QCameraFocusControl()
+    , m_session(session)
+    , m_focusMode(QCameraFocus::AutoFocus)
+    , m_focusPointMode(QCameraFocus::FocusPointAuto)
+    , m_actualFocusPoint(0.5, 0.5)
+    , m_continuousPictureFocusSupported(false)
+    , m_continuousVideoFocusSupported(false)
+{
+    connect(m_session, SIGNAL(opened()),
+            this, SLOT(onCameraOpened()));
+    connect(m_session, SIGNAL(captureModeChanged(QCamera::CaptureModes)),
+            this, SLOT(onCameraCaptureModeChanged()));
+}
+
+QCameraFocus::FocusModes QAndroidCameraFocusControl::focusMode() const
+{
+    return m_focusMode;
+}
+
+void QAndroidCameraFocusControl::setFocusMode(QCameraFocus::FocusModes mode)
+{
+    if (m_focusMode == mode || !m_session->camera() || !isFocusModeSupported(mode))
+        return;
+
+    QString focusMode = QLatin1String("fixed");
+
+    if (mode.testFlag(QCameraFocus::HyperfocalFocus)) {
+        focusMode = QLatin1String("edof");
+    } else if (mode.testFlag(QCameraFocus::ManualFocus)) {
+        focusMode = QLatin1String("fixed");
+    } else if (mode.testFlag(QCameraFocus::AutoFocus)) {
+        focusMode = QLatin1String("auto");
+    } else if (mode.testFlag(QCameraFocus::MacroFocus)) {
+        focusMode = QLatin1String("macro");
+    } else if (mode.testFlag(QCameraFocus::ContinuousFocus)) {
+        if ((m_session->captureMode().testFlag(QCamera::CaptureVideo) && m_continuousVideoFocusSupported)
+                || !m_continuousPictureFocusSupported) {
+            focusMode = QLatin1String("continuous-video");
+        } else {
+            focusMode = QLatin1String("continuous-picture");
+        }
+    } else if (mode.testFlag(QCameraFocus::InfinityFocus)) {
+        focusMode = QLatin1String("infinity");
+    }
+
+    m_session->camera()->setFocusMode(focusMode);
+
+    // reset focus position
+    m_session->camera()->cancelAutoFocus();
+
+    m_focusMode = mode;
+    emit focusModeChanged(m_focusMode);
+}
+
+bool QAndroidCameraFocusControl::isFocusModeSupported(QCameraFocus::FocusModes mode) const
+{
+    return m_supportedFocusModes.contains(mode);
+}
+
+QCameraFocus::FocusPointMode QAndroidCameraFocusControl::focusPointMode() const
+{
+    return m_focusPointMode;
+}
+
+void QAndroidCameraFocusControl::setFocusPointMode(QCameraFocus::FocusPointMode mode)
+{
+    if (!m_session->camera() || m_focusPointMode == mode || !isFocusPointModeSupported(mode))
+        return;
+
+    m_focusPointMode = mode;
+
+    if (mode == QCameraFocus::FocusPointCustom) {
+        m_actualFocusPoint = m_customFocusPoint;
+    } else {
+        // FocusPointAuto | FocusPointCenter
+        // note: there is no way to know the actual focus point in FocusPointAuto mode,
+        // so just report the focus point to be at the center of the frame
+        m_actualFocusPoint = QPointF(0.5, 0.5);
+    }
+
+    updateFocusZones();
+    setCameraFocusArea();
+
+    emit focusPointModeChanged(mode);
+}
+
+bool QAndroidCameraFocusControl::isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const
+{
+    return m_supportedFocusPointModes.contains(mode);
+}
+
+QPointF QAndroidCameraFocusControl::customFocusPoint() const
+{
+    return m_customFocusPoint;
+}
+
+void QAndroidCameraFocusControl::setCustomFocusPoint(const QPointF &point)
+{
+    if (m_customFocusPoint == point)
+        return;
+
+    m_customFocusPoint = point;
+    emit customFocusPointChanged(m_customFocusPoint);
+
+    if (m_focusPointMode == QCameraFocus::FocusPointCustom) {
+        m_actualFocusPoint = m_customFocusPoint;
+        updateFocusZones();
+        setCameraFocusArea();
+    }
+}
+
+QCameraFocusZoneList QAndroidCameraFocusControl::focusZones() const
+{
+    return m_focusZones;
+}
+
+void QAndroidCameraFocusControl::onCameraOpened()
+{
+    connect(m_session->camera(), SIGNAL(previewSizeChanged()),
+            this, SLOT(onViewportSizeChanged()));
+    connect(m_session->camera(), SIGNAL(autoFocusStarted()),
+            this, SLOT(onAutoFocusStarted()));
+    connect(m_session->camera(), SIGNAL(autoFocusComplete(bool)),
+            this, SLOT(onAutoFocusComplete(bool)));
+
+    m_supportedFocusModes.clear();
+    m_continuousPictureFocusSupported = false;
+    m_continuousVideoFocusSupported = false;
+
+    m_focusPointMode = QCameraFocus::FocusPointAuto;
+    m_actualFocusPoint = QPointF(0.5, 0.5);
+    m_customFocusPoint = QPointF();
+    m_supportedFocusPointModes.clear();
+    m_focusZones.clear();
+
+    QStringList focusModes = m_session->camera()->getSupportedFocusModes();
+    for (int i = 0; i < focusModes.size(); ++i) {
+        const QString &focusMode = focusModes.at(i);
+        if (focusMode == QLatin1String("auto")) {
+            m_supportedFocusModes << QCameraFocus::AutoFocus;
+        } else if (focusMode == QLatin1String("continuous-picture")) {
+            m_supportedFocusModes << QCameraFocus::ContinuousFocus;
+            m_continuousPictureFocusSupported = true;
+        } else if (focusMode == QLatin1String("continuous-video")) {
+            m_supportedFocusModes << QCameraFocus::ContinuousFocus;
+            m_continuousVideoFocusSupported = true;
+        } else if (focusMode == QLatin1String("edof")) {
+            m_supportedFocusModes << QCameraFocus::HyperfocalFocus;
+        } else if (focusMode == QLatin1String("fixed")) {
+            m_supportedFocusModes << QCameraFocus::ManualFocus;
+        } else if (focusMode == QLatin1String("infinity")) {
+            m_supportedFocusModes << QCameraFocus::InfinityFocus;
+        } else if (focusMode == QLatin1String("macro")) {
+            m_supportedFocusModes << QCameraFocus::MacroFocus;
+        }
+    }
+
+    m_supportedFocusPointModes << QCameraFocus::FocusPointAuto;
+    if (m_session->camera()->getMaxNumFocusAreas() > 0)
+        m_supportedFocusPointModes << QCameraFocus::FocusPointCenter << QCameraFocus::FocusPointCustom;
+
+    emit focusModeChanged(focusMode());
+    emit focusPointModeChanged(m_focusPointMode);
+    emit customFocusPointChanged(m_customFocusPoint);
+    emit focusZonesChanged();
+}
+
+void QAndroidCameraFocusControl::updateFocusZones(QCameraFocusZone::FocusZoneStatus status)
+{
+    if (!m_session->camera())
+        return;
+
+    // create a focus zone (50x50 pixel) around the focus point
+    m_focusZones.clear();
+
+    if (m_actualFocusPoint.isNull())
+        return;
+
+    QSize viewportSize = m_session->camera()->previewSize();
+    QSizeF focusSize(50.f / viewportSize.width(), 50.f / viewportSize.height());
+    float x = qBound(0.f,
+                     m_actualFocusPoint.x() - (focusSize.width() / 2),
+                     1.f - focusSize.width());
+    float y = qBound(0.f,
+                     m_actualFocusPoint.y() - (focusSize.height() / 2),
+                     1.f - focusSize.height());
+
+    QRectF area(QPointF(x, y), focusSize);
+
+    m_focusZones.append(QCameraFocusZone(area, status));
+
+    emit focusZonesChanged();
+}
+
+void QAndroidCameraFocusControl::setCameraFocusArea()
+{
+    QList<QRect> areas;
+    if (m_focusPointMode != QCameraFocus::FocusPointAuto) {
+        // in FocusPointAuto mode, leave the area list empty
+        // to let the driver choose the focus point.
+
+        for (int i = 0; i < m_focusZones.size(); ++i)
+            areas.append(adjustedArea(m_focusZones.at(i).area()));
+
+    }
+    m_session->camera()->setFocusAreas(areas);
+}
+
+void QAndroidCameraFocusControl::onViewportSizeChanged()
+{
+    QCameraFocusZone::FocusZoneStatus status = QCameraFocusZone::Selected;
+    if (!m_focusZones.isEmpty())
+        status = m_focusZones.at(0).status();
+    updateFocusZones(status);
+}
+
+void QAndroidCameraFocusControl::onCameraCaptureModeChanged()
+{
+    if (m_focusMode == QCameraFocus::ContinuousFocus) {
+        QString focusMode;
+        if ((m_session->captureMode().testFlag(QCamera::CaptureVideo) && m_continuousVideoFocusSupported)
+                || !m_continuousPictureFocusSupported) {
+            focusMode = QLatin1String("continuous-video");
+        } else {
+            focusMode = QLatin1String("continuous-picture");
+        }
+        m_session->camera()->setFocusMode(focusMode);
+        m_session->camera()->cancelAutoFocus();
+    }
+}
+
+void QAndroidCameraFocusControl::onAutoFocusStarted()
+{
+    updateFocusZones(QCameraFocusZone::Selected);
+}
+
+void QAndroidCameraFocusControl::onAutoFocusComplete(bool success)
+{
+    if (success)
+        updateFocusZones(QCameraFocusZone::Focused);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerafocuscontrol.h b/src/plugins/android/src/mediacapture/qandroidcamerafocuscontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..4311e78ba3464c5809ab8e34159ddb0a5ea2ee77
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcamerafocuscontrol.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDCAMERAFOCUSCONTROL_H
+#define QANDROIDCAMERAFOCUSCONTROL_H
+
+#include <qcamerafocuscontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraSession;
+
+class QAndroidCameraFocusControl : public QCameraFocusControl
+{
+    Q_OBJECT
+public:
+    explicit QAndroidCameraFocusControl(QAndroidCameraSession *session);
+
+    QCameraFocus::FocusModes focusMode() const Q_DECL_OVERRIDE;
+    void setFocusMode(QCameraFocus::FocusModes mode) Q_DECL_OVERRIDE;
+    bool isFocusModeSupported(QCameraFocus::FocusModes mode) const Q_DECL_OVERRIDE;
+    QCameraFocus::FocusPointMode focusPointMode() const Q_DECL_OVERRIDE;
+    void setFocusPointMode(QCameraFocus::FocusPointMode mode) Q_DECL_OVERRIDE;
+    bool isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const Q_DECL_OVERRIDE;
+    QPointF customFocusPoint() const Q_DECL_OVERRIDE;
+    void setCustomFocusPoint(const QPointF &point) Q_DECL_OVERRIDE;
+    QCameraFocusZoneList focusZones() const Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+    void onCameraOpened();
+    void onViewportSizeChanged();
+    void onCameraCaptureModeChanged();
+    void onAutoFocusStarted();
+    void onAutoFocusComplete(bool success);
+
+private:
+    void updateFocusZones(QCameraFocusZone::FocusZoneStatus status = QCameraFocusZone::Selected);
+    void setCameraFocusArea();
+
+    QAndroidCameraSession *m_session;
+
+    QCameraFocus::FocusModes m_focusMode;
+    QCameraFocus::FocusPointMode m_focusPointMode;
+    QPointF m_actualFocusPoint;
+    QPointF m_customFocusPoint;
+    QCameraFocusZoneList m_focusZones;
+
+    QList<QCameraFocus::FocusModes> m_supportedFocusModes;
+    bool m_continuousPictureFocusSupported;
+    bool m_continuousVideoFocusSupported;
+
+    QList<QCameraFocus::FocusPointMode> m_supportedFocusPointModes;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDCAMERAFOCUSCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidcameraimagecapturecontrol.cpp b/src/plugins/android/src/mediacapture/qandroidcameraimagecapturecontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3c04d292fe2782cc40c94fd6f6fa6027955ba677
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameraimagecapturecontrol.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidcameraimagecapturecontrol.h"
+
+#include "qandroidcamerasession.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidCameraImageCaptureControl::QAndroidCameraImageCaptureControl(QAndroidCameraSession *session)
+    : QCameraImageCaptureControl()
+    , m_session(session)
+{
+    connect(m_session, SIGNAL(readyForCaptureChanged(bool)), this, SIGNAL(readyForCaptureChanged(bool)));
+    connect(m_session, SIGNAL(imageExposed(int)), this, SIGNAL(imageExposed(int)));
+    connect(m_session, SIGNAL(imageCaptured(int,QImage)), this, SIGNAL(imageCaptured(int,QImage)));
+    connect(m_session, SIGNAL(imageMetadataAvailable(int,QString,QVariant)), this, SIGNAL(imageMetadataAvailable(int,QString,QVariant)));
+    connect(m_session, SIGNAL(imageAvailable(int,QVideoFrame)), this, SIGNAL(imageAvailable(int,QVideoFrame)));
+    connect(m_session, SIGNAL(imageSaved(int,QString)), this, SIGNAL(imageSaved(int,QString)));
+    connect(m_session, SIGNAL(imageCaptureError(int,int,QString)), this, SIGNAL(error(int,int,QString)));
+}
+
+bool QAndroidCameraImageCaptureControl::isReadyForCapture() const
+{
+    return m_session->isReadyForCapture();
+}
+
+QCameraImageCapture::DriveMode QAndroidCameraImageCaptureControl::driveMode() const
+{
+    return m_session->driveMode();
+}
+
+void QAndroidCameraImageCaptureControl::setDriveMode(QCameraImageCapture::DriveMode mode)
+{
+    m_session->setDriveMode(mode);
+}
+
+int QAndroidCameraImageCaptureControl::capture(const QString &fileName)
+{
+    return m_session->capture(fileName);
+}
+
+void QAndroidCameraImageCaptureControl::cancelCapture()
+{
+    m_session->cancelCapture();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcameraimagecapturecontrol.h b/src/plugins/android/src/mediacapture/qandroidcameraimagecapturecontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..f69913b14b557c4739a8d7a6e5ee0378bb1a29c1
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameraimagecapturecontrol.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDCAMERAIMAGECAPTURECONTROL_H
+#define QANDROIDCAMERAIMAGECAPTURECONTROL_H
+
+#include <qcameraimagecapturecontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraSession;
+
+class QAndroidCameraImageCaptureControl : public QCameraImageCaptureControl
+{
+    Q_OBJECT
+public:
+    explicit QAndroidCameraImageCaptureControl(QAndroidCameraSession *session);
+
+    bool isReadyForCapture() const Q_DECL_OVERRIDE;
+
+    QCameraImageCapture::DriveMode driveMode() const Q_DECL_OVERRIDE;
+    void setDriveMode(QCameraImageCapture::DriveMode mode) Q_DECL_OVERRIDE;
+
+    int capture(const QString &fileName) Q_DECL_OVERRIDE;
+    void cancelCapture() Q_DECL_OVERRIDE;
+
+private:
+    QAndroidCameraSession *m_session;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDCAMERAIMAGECAPTURECONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidcameraimageprocessingcontrol.cpp b/src/plugins/android/src/mediacapture/qandroidcameraimageprocessingcontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ec5a3bcbfc367b285cf7d3df13dc23c804d220fd
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameraimageprocessingcontrol.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidcameraimageprocessingcontrol.h"
+
+#include "qandroidcamerasession.h"
+#include "jcamera.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidCameraImageProcessingControl::QAndroidCameraImageProcessingControl(QAndroidCameraSession *session)
+    : QCameraImageProcessingControl()
+    , m_session(session)
+{
+    connect(m_session, SIGNAL(opened()),
+            this, SLOT(onCameraOpened()));
+}
+
+bool QAndroidCameraImageProcessingControl::isParameterSupported(ProcessingParameter parameter) const
+{
+    return (parameter == QCameraImageProcessingControl::WhiteBalancePreset);
+}
+
+bool QAndroidCameraImageProcessingControl::isParameterValueSupported(ProcessingParameter parameter,
+                                                                     const QVariant &value) const
+{
+    if (parameter != QCameraImageProcessingControl::WhiteBalancePreset)
+        return false;
+
+    if (!m_session->camera())
+        return false;
+
+    return m_supportedWhiteBalanceModes.contains(value.value<QCameraImageProcessing::WhiteBalanceMode>());
+}
+
+QVariant QAndroidCameraImageProcessingControl::parameter(ProcessingParameter parameter) const
+{
+    if (parameter != QCameraImageProcessingControl::WhiteBalancePreset)
+        return QVariant();
+
+    if (!m_session->camera())
+        return QVariant();
+
+    QString wb = m_session->camera()->getWhiteBalance();
+    QCameraImageProcessing::WhiteBalanceMode mode = m_supportedWhiteBalanceModes.key(wb, QCameraImageProcessing::WhiteBalanceAuto);
+
+    return QVariant::fromValue(mode);
+}
+
+void QAndroidCameraImageProcessingControl::setParameter(ProcessingParameter parameter, const QVariant &value)
+{
+    if (parameter != QCameraImageProcessingControl::WhiteBalancePreset)
+        return;
+
+    if (!m_session->camera())
+        return;
+
+    QString wb = m_supportedWhiteBalanceModes.value(value.value<QCameraImageProcessing::WhiteBalanceMode>(), QString());
+    if (!wb.isEmpty())
+        m_session->camera()->setWhiteBalance(wb);
+}
+
+void QAndroidCameraImageProcessingControl::onCameraOpened()
+{
+    m_supportedWhiteBalanceModes.clear();
+    QStringList whiteBalanceModes = m_session->camera()->getSupportedWhiteBalance();
+    for (int i = 0; i < whiteBalanceModes.size(); ++i) {
+        const QString &wb = whiteBalanceModes.at(i);
+        if (wb == QLatin1String("auto")) {
+            m_supportedWhiteBalanceModes.insert(QCameraImageProcessing::WhiteBalanceAuto,
+                                                QStringLiteral("auto"));
+        } else if (wb == QLatin1String("cloudy-daylight")) {
+            m_supportedWhiteBalanceModes.insert(QCameraImageProcessing::WhiteBalanceCloudy,
+                                                QStringLiteral("cloudy-daylight"));
+        } else if (wb == QLatin1String("daylight")) {
+            m_supportedWhiteBalanceModes.insert(QCameraImageProcessing::WhiteBalanceSunlight,
+                                                QStringLiteral("daylight"));
+        } else if (wb == QLatin1String("fluorescent")) {
+            m_supportedWhiteBalanceModes.insert(QCameraImageProcessing::WhiteBalanceFluorescent,
+                                                QStringLiteral("fluorescent"));
+        } else if (wb == QLatin1String("incandescent")) {
+            m_supportedWhiteBalanceModes.insert(QCameraImageProcessing::WhiteBalanceTungsten,
+                                                QStringLiteral("incandescent"));
+        } else if (wb == QLatin1String("shade")) {
+            m_supportedWhiteBalanceModes.insert(QCameraImageProcessing::WhiteBalanceShade,
+                                                QStringLiteral("shade"));
+        } else if (wb == QLatin1String("twilight")) {
+            m_supportedWhiteBalanceModes.insert(QCameraImageProcessing::WhiteBalanceSunset,
+                                                QStringLiteral("twilight"));
+        } else if (wb == QLatin1String("warm-fluorescent")) {
+            m_supportedWhiteBalanceModes.insert(QCameraImageProcessing::WhiteBalanceFlash,
+                                                QStringLiteral("warm-fluorescent"));
+        }
+    }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcameraimageprocessingcontrol.h b/src/plugins/android/src/mediacapture/qandroidcameraimageprocessingcontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..3ef3c31443a4991fbfdc942af0a8a8b0c61ac1ea
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameraimageprocessingcontrol.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDCAMERAIMAGEPROCESSINGCONTROL_H
+#define QANDROIDCAMERAIMAGEPROCESSINGCONTROL_H
+
+#include <qcameraimageprocessingcontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraSession;
+
+class QAndroidCameraImageProcessingControl : public QCameraImageProcessingControl
+{
+    Q_OBJECT
+public:
+    explicit QAndroidCameraImageProcessingControl(QAndroidCameraSession *session);
+
+    bool isParameterSupported(ProcessingParameter) const Q_DECL_OVERRIDE;
+    bool isParameterValueSupported(ProcessingParameter parameter, const QVariant &value) const Q_DECL_OVERRIDE;
+    QVariant parameter(ProcessingParameter parameter) const Q_DECL_OVERRIDE;
+    void setParameter(ProcessingParameter parameter, const QVariant &value) Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+    void onCameraOpened();
+
+private:
+    QAndroidCameraSession *m_session;
+
+    QHash<QCameraImageProcessing::WhiteBalanceMode, QString> m_supportedWhiteBalanceModes;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDCAMERAIMAGEPROCESSINGCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidcameralockscontrol.cpp b/src/plugins/android/src/mediacapture/qandroidcameralockscontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d9f20ec043a17edeb77e3acf75d2a95c865dfa40
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameralockscontrol.cpp
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidcameralockscontrol.h"
+
+#include "qandroidcamerasession.h"
+#include "jcamera.h"
+#include <qtimer.h>
+
+QT_BEGIN_NAMESPACE
+
+QAndroidCameraLocksControl::QAndroidCameraLocksControl(QAndroidCameraSession *session)
+    : QCameraLocksControl()
+    , m_session(session)
+    , m_supportedLocks(QCamera::NoLock)
+    , m_focusLockStatus(QCamera::Unlocked)
+    , m_exposureLockStatus(QCamera::Unlocked)
+    , m_whiteBalanceLockStatus(QCamera::Unlocked)
+{
+    connect(m_session, SIGNAL(opened()),
+            this, SLOT(onCameraOpened()));
+
+    m_recalculateTimer = new QTimer(this);
+    m_recalculateTimer->setInterval(1000);
+    m_recalculateTimer->setSingleShot(true);
+    connect(m_recalculateTimer, SIGNAL(timeout()), this, SLOT(onRecalculateTimeOut()));
+}
+
+QCamera::LockTypes QAndroidCameraLocksControl::supportedLocks() const
+{
+    return (QCamera::LockExposure | QCamera::LockWhiteBalance | QCamera::LockFocus);
+}
+
+QCamera::LockStatus QAndroidCameraLocksControl::lockStatus(QCamera::LockType lock) const
+{
+    if (!m_supportedLocks.testFlag(lock) || !m_session->camera())
+        return QCamera::Locked;
+
+    if (lock == QCamera::LockFocus)
+        return m_focusLockStatus;
+
+    if (lock == QCamera::LockExposure)
+        return m_exposureLockStatus;
+
+    if (lock == QCamera::LockWhiteBalance)
+        return m_whiteBalanceLockStatus;
+
+    return QCamera::Locked;
+}
+
+void QAndroidCameraLocksControl::searchAndLock(QCamera::LockTypes locks)
+{
+    if (!m_session->camera())
+        return;
+
+    // filter out unsupported locks
+    locks &= m_supportedLocks;
+
+    if (locks.testFlag(QCamera::LockFocus)) {
+        QString focusMode = m_session->camera()->getFocusMode();
+        if (focusMode == QLatin1String("auto")
+                || focusMode == QLatin1String("macro")
+                || focusMode == QLatin1String("continuous-picture")
+                || focusMode == QLatin1String("continuous-video")) {
+
+            if (m_focusLockStatus == QCamera::Searching)
+                m_session->camera()->cancelAutoFocus();
+            else
+                setFocusLockStatus(QCamera::Searching, QCamera::UserRequest);
+
+            m_session->camera()->autoFocus();
+
+        } else {
+            setFocusLockStatus(QCamera::Locked, QCamera::LockAcquired);
+        }
+    }
+
+    if (locks.testFlag(QCamera::LockExposure) && m_exposureLockStatus != QCamera::Searching) {
+        if (m_session->camera()->getAutoExposureLock()) {
+            // if already locked, unlock and give some time to recalculate exposure
+            m_session->camera()->setAutoExposureLock(false);
+            setExposureLockStatus(QCamera::Searching, QCamera::UserRequest);
+        } else {
+            m_session->camera()->setAutoExposureLock(true);
+            setExposureLockStatus(QCamera::Locked, QCamera::LockAcquired);
+        }
+    }
+
+    if (locks.testFlag(QCamera::LockWhiteBalance) && m_whiteBalanceLockStatus != QCamera::Searching) {
+        if (m_session->camera()->getAutoWhiteBalanceLock()) {
+            // if already locked, unlock and give some time to recalculate white balance
+            m_session->camera()->setAutoWhiteBalanceLock(false);
+            setWhiteBalanceLockStatus(QCamera::Searching, QCamera::UserRequest);
+        } else {
+            m_session->camera()->setAutoWhiteBalanceLock(true);
+            setWhiteBalanceLockStatus(QCamera::Locked, QCamera::LockAcquired);
+        }
+    }
+
+    if (m_exposureLockStatus == QCamera::Searching || m_whiteBalanceLockStatus == QCamera::Searching)
+        m_recalculateTimer->start();
+}
+
+void QAndroidCameraLocksControl::unlock(QCamera::LockTypes locks)
+{
+    if (!m_session->camera())
+        return;
+
+    if (m_recalculateTimer->isActive())
+        m_recalculateTimer->stop();
+
+    // filter out unsupported locks
+    locks &= m_supportedLocks;
+
+    if (locks.testFlag(QCamera::LockFocus)) {
+        m_session->camera()->cancelAutoFocus();
+        setFocusLockStatus(QCamera::Unlocked, QCamera::UserRequest);
+    }
+
+    if (locks.testFlag(QCamera::LockExposure)) {
+        m_session->camera()->setAutoExposureLock(false);
+        setExposureLockStatus(QCamera::Unlocked, QCamera::UserRequest);
+    }
+
+    if (locks.testFlag(QCamera::LockWhiteBalance)) {
+        m_session->camera()->setAutoWhiteBalanceLock(false);
+        setWhiteBalanceLockStatus(QCamera::Unlocked, QCamera::UserRequest);
+    }
+}
+
+void QAndroidCameraLocksControl::onCameraOpened()
+{
+    m_supportedLocks = QCamera::NoLock;
+    m_focusLockStatus = QCamera::Unlocked;
+    m_exposureLockStatus = QCamera::Unlocked;
+    m_whiteBalanceLockStatus = QCamera::Unlocked;
+
+    // check if focus lock is supported
+    QStringList focusModes = m_session->camera()->getSupportedFocusModes();
+    for (int i = 0; i < focusModes.size(); ++i) {
+        const QString &focusMode = focusModes.at(i);
+        if (focusMode == QLatin1String("auto")
+                || focusMode == QLatin1String("continuous-picture")
+                || focusMode == QLatin1String("continuous-video")
+                || focusMode == QLatin1String("macro")) {
+
+            m_supportedLocks |= QCamera::LockFocus;
+            setFocusLockStatus(QCamera::Unlocked, QCamera::UserRequest);
+
+            connect(m_session->camera(), SIGNAL(autoFocusComplete(bool)),
+                    this, SLOT(onCameraAutoFocusComplete(bool)));
+
+            break;
+        }
+    }
+
+    if (m_session->camera()->isAutoExposureLockSupported()) {
+        m_supportedLocks |= QCamera::LockExposure;
+        setExposureLockStatus(QCamera::Unlocked, QCamera::UserRequest);
+    }
+
+    if (m_session->camera()->isAutoWhiteBalanceLockSupported()) {
+        m_supportedLocks |= QCamera::LockWhiteBalance;
+        setWhiteBalanceLockStatus(QCamera::Unlocked, QCamera::UserRequest);
+
+        connect(m_session->camera(), SIGNAL(whiteBalanceChanged()),
+                this, SLOT(onWhiteBalanceChanged()));
+    }
+}
+
+void QAndroidCameraLocksControl::onCameraAutoFocusComplete(bool success)
+{
+    m_focusLockStatus = success ? QCamera::Locked : QCamera::Unlocked;
+    QCamera::LockChangeReason reason = success ? QCamera::LockAcquired : QCamera::LockFailed;
+    emit lockStatusChanged(QCamera::LockFocus, m_focusLockStatus, reason);
+}
+
+void QAndroidCameraLocksControl::onRecalculateTimeOut()
+{
+    if (m_exposureLockStatus == QCamera::Searching) {
+        m_session->camera()->setAutoExposureLock(true);
+        setExposureLockStatus(QCamera::Locked, QCamera::LockAcquired);
+    }
+
+    if (m_whiteBalanceLockStatus == QCamera::Searching) {
+        m_session->camera()->setAutoWhiteBalanceLock(true);
+        setWhiteBalanceLockStatus(QCamera::Locked, QCamera::LockAcquired);
+    }
+}
+
+void QAndroidCameraLocksControl::onWhiteBalanceChanged()
+{
+    // changing the white balance mode releases the white balance lock
+    if (m_whiteBalanceLockStatus != QCamera::Unlocked)
+        setWhiteBalanceLockStatus(QCamera::Unlocked, QCamera::LockLost);
+}
+
+void QAndroidCameraLocksControl::setFocusLockStatus(QCamera::LockStatus status, QCamera::LockChangeReason reason)
+{
+    m_focusLockStatus = status;
+    emit lockStatusChanged(QCamera::LockFocus, m_focusLockStatus, reason);
+}
+
+void QAndroidCameraLocksControl::setWhiteBalanceLockStatus(QCamera::LockStatus status, QCamera::LockChangeReason reason)
+{
+    m_whiteBalanceLockStatus = status;
+    emit lockStatusChanged(QCamera::LockWhiteBalance, m_whiteBalanceLockStatus, reason);
+}
+
+void QAndroidCameraLocksControl::setExposureLockStatus(QCamera::LockStatus status, QCamera::LockChangeReason reason)
+{
+    m_exposureLockStatus = status;
+    emit lockStatusChanged(QCamera::LockExposure, m_exposureLockStatus, reason);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcameralockscontrol.h b/src/plugins/android/src/mediacapture/qandroidcameralockscontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..d49821bff41374e7f2f09e6858d9f67069f161cc
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcameralockscontrol.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDCAMERALOCKSCONTROL_H
+#define QANDROIDCAMERALOCKSCONTROL_H
+
+#include <qcameralockscontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraSession;
+class QTimer;
+
+class QAndroidCameraLocksControl : public QCameraLocksControl
+{
+    Q_OBJECT
+public:
+    explicit QAndroidCameraLocksControl(QAndroidCameraSession *session);
+
+    QCamera::LockTypes supportedLocks() const Q_DECL_OVERRIDE;
+    QCamera::LockStatus lockStatus(QCamera::LockType lock) const Q_DECL_OVERRIDE;
+    void searchAndLock(QCamera::LockTypes locks) Q_DECL_OVERRIDE;
+    void unlock(QCamera::LockTypes locks) Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+    void onCameraOpened();
+    void onCameraAutoFocusComplete(bool success);
+    void onRecalculateTimeOut();
+    void onWhiteBalanceChanged();
+
+private:
+    void setFocusLockStatus(QCamera::LockStatus status, QCamera::LockChangeReason reason);
+    void setWhiteBalanceLockStatus(QCamera::LockStatus status, QCamera::LockChangeReason reason);
+    void setExposureLockStatus(QCamera::LockStatus status, QCamera::LockChangeReason reason);
+
+    QAndroidCameraSession *m_session;
+
+    QTimer *m_recalculateTimer;
+
+    QCamera::LockTypes m_supportedLocks;
+
+    QCamera::LockStatus m_focusLockStatus;
+    QCamera::LockStatus m_exposureLockStatus;
+    QCamera::LockStatus m_whiteBalanceLockStatus;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDCAMERALOCKSCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..761b716d156d6eb976d24c1a623a749ce5da34ec
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
@@ -0,0 +1,553 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidcamerasession.h"
+
+#include "jcamera.h"
+#include "jmultimediautils.h"
+#include "qandroidvideooutput.h"
+#include "qandroidmultimediautils.h"
+#include <QtConcurrent/qtconcurrentrun.h>
+#include <qfile.h>
+#include <qguiapplication.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+static void textureReadyCallback(void *context)
+{
+    if (context)
+        reinterpret_cast<QAndroidCameraSession *>(context)->onSurfaceTextureReady();
+}
+
+QAndroidCameraSession::QAndroidCameraSession(QObject *parent)
+    : QObject(parent)
+    , m_selectedCamera(0)
+    , m_camera(0)
+    , m_nativeOrientation(0)
+    , m_videoOutput(0)
+    , m_captureMode(QCamera::CaptureViewfinder)
+    , m_state(QCamera::UnloadedState)
+    , m_savedState(-1)
+    , m_status(QCamera::UnloadedStatus)
+    , m_previewStarted(false)
+    , m_imageSettingsDirty(true)
+    , m_captureDestination(QCameraImageCapture::CaptureToFile)
+    , m_captureImageDriveMode(QCameraImageCapture::SingleImageCapture)
+    , m_lastImageCaptureId(0)
+    , m_readyForCapture(false)
+    , m_captureCanceled(false)
+    , m_currentImageCaptureId(-1)
+{
+    if (qApp) {
+        connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
+                this, SLOT(onApplicationStateChanged(Qt::ApplicationState)));
+    }
+}
+
+QAndroidCameraSession::~QAndroidCameraSession()
+{
+    close();
+}
+
+void QAndroidCameraSession::setCaptureMode(QCamera::CaptureModes mode)
+{
+    if (m_captureMode == mode || !isCaptureModeSupported(mode))
+        return;
+
+    m_captureMode = mode;
+    emit captureModeChanged(m_captureMode);
+
+    if (m_previewStarted && m_captureMode.testFlag(QCamera::CaptureStillImage))
+        adjustViewfinderSize(m_imageSettings.resolution());
+}
+
+bool QAndroidCameraSession::isCaptureModeSupported(QCamera::CaptureModes mode) const
+{
+    if (mode & (QCamera::CaptureStillImage & QCamera::CaptureVideo))
+        return false;
+
+    return true;
+}
+
+void QAndroidCameraSession::setState(QCamera::State state)
+{
+    // If the application is inactive, the camera shouldn't be started. Save the desired state
+    // instead and it will be set when the application becomes active.
+    if (qApp->applicationState() != Qt::ApplicationActive) {
+        m_savedState = state;
+        return;
+    }
+
+    if (m_state == state)
+        return;
+
+    switch (state) {
+    case QCamera::UnloadedState:
+        close();
+        break;
+    case QCamera::LoadedState:
+    case QCamera::ActiveState:
+        if (!m_camera && !open()) {
+            emit error(QCamera::CameraError, QStringLiteral("Failed to open camera"));
+            return;
+        }
+        if (state == QCamera::ActiveState)
+            startPreview();
+        else if (state == QCamera::LoadedState)
+            stopPreview();
+        break;
+    }
+
+     m_state = state;
+     emit stateChanged(m_state);
+}
+
+bool QAndroidCameraSession::open()
+{
+    close();
+
+    m_status = QCamera::LoadingStatus;
+    emit statusChanged(m_status);
+
+    m_camera = JCamera::open(m_selectedCamera);
+
+    if (m_camera) {
+        connect(m_camera, SIGNAL(pictureExposed()), this, SLOT(onCameraPictureExposed()));
+        connect(m_camera, SIGNAL(pictureCaptured(QByteArray)), this, SLOT(onCameraPictureCaptured(QByteArray)));
+        m_nativeOrientation = m_camera->getNativeOrientation();
+        m_status = QCamera::LoadedStatus;
+        emit opened();
+    } else {
+        m_status = QCamera::UnavailableStatus;
+    }
+
+    emit statusChanged(m_status);
+
+    return m_camera != 0;
+}
+
+void QAndroidCameraSession::close()
+{
+    if (!m_camera)
+        return;
+
+    stopPreview();
+
+    m_status = QCamera::UnloadingStatus;
+    emit statusChanged(m_status);
+
+    m_readyForCapture = false;
+    m_currentImageCaptureId = -1;
+    m_currentImageCaptureFileName.clear();
+    m_imageSettingsDirty = true;
+
+    m_camera->release();
+    delete m_camera;
+    m_camera = 0;
+
+    m_status = QCamera::UnloadedStatus;
+    emit statusChanged(m_status);
+}
+
+void QAndroidCameraSession::setVideoPreview(QAndroidVideoOutput *videoOutput)
+{
+    if (m_videoOutput)
+        m_videoOutput->stop();
+
+    m_videoOutput = videoOutput;
+}
+
+void QAndroidCameraSession::adjustViewfinderSize(const QSize &captureSize, bool restartPreview)
+{
+    if (!m_camera)
+        return;
+
+    QSize viewfinderResolution = m_camera->previewSize();
+    const qreal aspectRatio = qreal(captureSize.width()) / qreal(captureSize.height());
+    if (qFuzzyCompare(aspectRatio, qreal(viewfinderResolution.width()) / qreal(viewfinderResolution.height())))
+        return;
+
+    QList<QSize> previewSizes = m_camera->getSupportedPreviewSizes();
+    for (int i = previewSizes.count() - 1; i >= 0; --i) {
+        const QSize &size = previewSizes.at(i);
+        // search for viewfinder resolution with the same aspect ratio
+        if (qFuzzyCompare(aspectRatio, (static_cast<qreal>(size.width())/static_cast<qreal>(size.height())))) {
+            viewfinderResolution = size;
+            break;
+        }
+    }
+
+    if (m_camera->previewSize() != viewfinderResolution) {
+        if (m_videoOutput)
+            m_videoOutput->setVideoSize(viewfinderResolution);
+
+        // if preview is started, we have to stop it first before changing its size
+        if (m_previewStarted && restartPreview)
+            m_camera->stopPreview();
+
+        m_camera->setPreviewSize(viewfinderResolution);
+
+        // restart preview
+        if (m_previewStarted && restartPreview)
+            m_camera->startPreview();
+    }
+}
+
+void QAndroidCameraSession::startPreview()
+{
+    if (!m_camera || m_previewStarted)
+        return;
+
+    m_status = QCamera::StartingStatus;
+    emit statusChanged(m_status);
+
+    applyImageSettings();
+    adjustViewfinderSize(m_imageSettings.resolution());
+
+    if (m_videoOutput) {
+        if (m_videoOutput->isTextureReady())
+            m_camera->setPreviewTexture(m_videoOutput->surfaceTexture());
+        else
+            m_videoOutput->setTextureReadyCallback(textureReadyCallback, this);
+    }
+
+    JMultimediaUtils::enableOrientationListener(true);
+
+    m_camera->startPreview();
+    m_previewStarted = true;
+
+    m_status = QCamera::ActiveStatus;
+    emit statusChanged(m_status);
+
+    setReadyForCapture(true);
+}
+
+void QAndroidCameraSession::stopPreview()
+{
+    if (!m_camera || !m_previewStarted)
+        return;
+
+    m_status = QCamera::StoppingStatus;
+    emit statusChanged(m_status);
+
+    JMultimediaUtils::enableOrientationListener(false);
+
+    m_camera->stopPreview();
+    if (m_videoOutput)
+        m_videoOutput->stop();
+    m_previewStarted = false;
+
+    m_status = QCamera::LoadedStatus;
+    emit statusChanged(m_status);
+
+    setReadyForCapture(false);
+}
+
+void QAndroidCameraSession::setImageSettings(const QImageEncoderSettings &settings)
+{
+    if (m_imageSettings == settings)
+        return;
+
+    m_imageSettings = settings;
+    if (m_imageSettings.codec().isEmpty())
+        m_imageSettings.setCodec(QLatin1String("jpeg"));
+
+    m_imageSettingsDirty = true;
+
+    applyImageSettings();
+
+    if (m_readyForCapture && m_captureMode.testFlag(QCamera::CaptureStillImage))
+        adjustViewfinderSize(m_imageSettings.resolution());
+}
+
+int QAndroidCameraSession::currentCameraRotation() const
+{
+    if (!m_camera)
+        return 0;
+
+    // subtract natural camera orientation and physical device orientation
+    int rotation = 0;
+    int deviceOrientation = (JMultimediaUtils::getDeviceOrientation() + 45) / 90 * 90;
+    if (m_camera->getFacing() == JCamera::CameraFacingFront)
+        rotation = (m_nativeOrientation - deviceOrientation + 360) % 360;
+    else // back-facing camera
+        rotation = (m_nativeOrientation + deviceOrientation) % 360;
+
+    return rotation;
+}
+
+void QAndroidCameraSession::applyImageSettings()
+{
+    if (!m_camera || !m_imageSettingsDirty)
+        return;
+
+    const QSize requestedResolution = m_imageSettings.resolution();
+    const QList<QSize> supportedResolutions = m_camera->getSupportedPictureSizes();
+
+    if (!requestedResolution.isValid()) {
+        // if no resolution is set, use the highest supported one
+        m_imageSettings.setResolution(supportedResolutions.last());
+    } else if (!supportedResolutions.contains(requestedResolution)) {
+        // if the requested resolution is not supported, find the closest one
+        int reqPixelCount = requestedResolution.width() * requestedResolution.height();
+        QList<int> supportedPixelCounts;
+        for (int i = 0; i < supportedResolutions.size(); ++i) {
+            const QSize &s = supportedResolutions.at(i);
+            supportedPixelCounts.append(s.width() * s.height());
+        }
+        int closestIndex = qt_findClosestValue(supportedPixelCounts, reqPixelCount);
+        m_imageSettings.setResolution(supportedResolutions.at(closestIndex));
+    }
+
+    int jpegQuality = 100;
+    switch (m_imageSettings.quality()) {
+    case QMultimedia::VeryLowQuality:
+        jpegQuality = 20;
+        break;
+    case QMultimedia::LowQuality:
+        jpegQuality = 40;
+        break;
+    case QMultimedia::NormalQuality:
+        jpegQuality = 60;
+        break;
+    case QMultimedia::HighQuality:
+        jpegQuality = 80;
+        break;
+    case QMultimedia::VeryHighQuality:
+        jpegQuality = 100;
+        break;
+    }
+
+    m_camera->setPictureSize(m_imageSettings.resolution());
+    m_camera->setJpegQuality(jpegQuality);
+
+    m_imageSettingsDirty = false;
+}
+
+bool QAndroidCameraSession::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const
+{
+    return destination & (QCameraImageCapture::CaptureToFile | QCameraImageCapture::CaptureToBuffer);
+}
+
+QCameraImageCapture::CaptureDestinations QAndroidCameraSession::captureDestination() const
+{
+    return m_captureDestination;
+}
+
+void QAndroidCameraSession::setCaptureDestination(QCameraImageCapture::CaptureDestinations destination)
+{
+    if (m_captureDestination != destination) {
+        m_captureDestination = destination;
+        emit captureDestinationChanged(m_captureDestination);
+    }
+}
+
+bool QAndroidCameraSession::isReadyForCapture() const
+{
+    return m_status == QCamera::ActiveStatus && m_readyForCapture;
+}
+
+void QAndroidCameraSession::setReadyForCapture(bool ready)
+{
+    if (m_readyForCapture == ready)
+        return;
+
+    m_readyForCapture = ready;
+    emit readyForCaptureChanged(ready);
+}
+
+QCameraImageCapture::DriveMode QAndroidCameraSession::driveMode() const
+{
+    return m_captureImageDriveMode;
+}
+
+void QAndroidCameraSession::setDriveMode(QCameraImageCapture::DriveMode mode)
+{
+    m_captureImageDriveMode = mode;
+}
+
+int QAndroidCameraSession::capture(const QString &fileName)
+{
+    ++m_lastImageCaptureId;
+
+    if (!isReadyForCapture()) {
+        emit imageCaptureError(m_lastImageCaptureId, QCameraImageCapture::NotReadyError,
+                               tr("Camera not ready"));
+        return m_lastImageCaptureId;
+    }
+
+    if (m_captureImageDriveMode == QCameraImageCapture::SingleImageCapture) {
+        setReadyForCapture(false);
+
+        m_currentImageCaptureId = m_lastImageCaptureId;
+        m_currentImageCaptureFileName = fileName;
+
+        applyImageSettings();
+        adjustViewfinderSize(m_imageSettings.resolution());
+
+        // adjust picture rotation depending on the device orientation
+        m_camera->setRotation(currentCameraRotation());
+
+        m_camera->takePicture();
+    } else {
+        emit imageCaptureError(m_lastImageCaptureId, QCameraImageCapture::NotSupportedFeatureError,
+                               tr("Drive mode not supported"));
+    }
+
+    return m_lastImageCaptureId;
+}
+
+void QAndroidCameraSession::cancelCapture()
+{
+    if (m_readyForCapture)
+        return;
+
+    m_captureCanceled = true;
+}
+
+void QAndroidCameraSession::onCameraPictureExposed()
+{
+    if (m_captureCanceled)
+        return;
+
+    emit imageExposed(m_currentImageCaptureId);
+}
+
+void QAndroidCameraSession::onCameraPictureCaptured(const QByteArray &data)
+{
+    if (!m_captureCanceled) {
+        // generate a preview from the viewport
+        if (m_videoOutput)
+            emit imageCaptured(m_currentImageCaptureId, m_videoOutput->toImage());
+
+        // Loading and saving the captured image can be slow, do it in a separate thread
+        QtConcurrent::run(this, &QAndroidCameraSession::processCapturedImage,
+                          m_currentImageCaptureId,
+                          data,
+                          m_captureDestination,
+                          m_currentImageCaptureFileName);
+    }
+
+    m_captureCanceled = false;
+
+    // Preview needs to be restarted after taking a picture
+    m_camera->startPreview();
+
+    setReadyForCapture(true);
+}
+
+void QAndroidCameraSession::processCapturedImage(int id,
+                                                 const QByteArray &data,
+                                                 QCameraImageCapture::CaptureDestinations dest,
+                                                 const QString &fileName)
+{
+
+
+    if (dest & QCameraImageCapture::CaptureToFile) {
+        const QString actualFileName = m_mediaStorageLocation.generateFileName(fileName,
+                                                                               QAndroidMediaStorageLocation::Camera,
+                                                                               QLatin1String("IMG_"),
+                                                                               QLatin1String("jpg"));
+
+        QFile file(actualFileName);
+        if (file.open(QFile::WriteOnly)) {
+            if (file.write(data) == data.size()) {
+                // if the picture is saved into the standard picture location, register it
+                // with the Android media scanner so it appears immediately in apps
+                // such as the gallery.
+                QString standardLoc = JMultimediaUtils::getDefaultMediaDirectory(JMultimediaUtils::DCIM);
+                if (actualFileName.startsWith(standardLoc))
+                    JMultimediaUtils::registerMediaFile(actualFileName);
+
+                emit imageSaved(id, actualFileName);
+            } else {
+                emit imageCaptureError(id, QCameraImageCapture::OutOfSpaceError, file.errorString());
+            }
+        } else {
+            const QString errorMessage = tr("Could not open destination file: %1").arg(actualFileName);
+            emit imageCaptureError(id, QCameraImageCapture::ResourceError, errorMessage);
+        }
+    }
+
+    if (dest & QCameraImageCapture::CaptureToBuffer) {
+        QImage image;
+        const bool ok = image.loadFromData(data, "JPG");
+
+        if (ok) {
+            QVideoFrame frame(image);
+            emit imageAvailable(id, frame);
+        } else {
+            emit imageCaptureError(id, QCameraImageCapture::FormatError,
+                                   tr("Could not load JPEG data from captured image"));
+        }
+    }
+}
+
+void QAndroidCameraSession::onSurfaceTextureReady()
+{
+    if (m_camera && m_videoOutput)
+        m_camera->setPreviewTexture(m_videoOutput->surfaceTexture());
+}
+
+void QAndroidCameraSession::onApplicationStateChanged(Qt::ApplicationState state)
+{
+    switch (state) {
+    case Qt::ApplicationInactive:
+        if (m_state != QCamera::UnloadedState) {
+            m_savedState = m_state;
+            close();
+            m_state = QCamera::UnloadedState;
+            emit stateChanged(m_state);
+        }
+        break;
+    case Qt::ApplicationActive:
+        if (m_savedState != -1) {
+            setState(QCamera::State(m_savedState));
+            m_savedState = -1;
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.h b/src/plugins/android/src/mediacapture/qandroidcamerasession.h
new file mode 100644
index 0000000000000000000000000000000000000000..f1cf44eec2d7c4501b18985c63c052675a9570d2
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDCAMERASESSION_H
+#define QANDROIDCAMERASESSION_H
+
+#include <qcamera.h>
+#include <qmediaencodersettings.h>
+#include <QCameraImageCapture>
+#include "qandroidmediastoragelocation.h"
+
+QT_BEGIN_NAMESPACE
+
+class JCamera;
+class QAndroidVideoOutput;
+
+class QAndroidCameraSession : public QObject
+{
+    Q_OBJECT
+public:
+    explicit QAndroidCameraSession(QObject *parent = 0);
+    ~QAndroidCameraSession();
+
+    void setSelectedCamera(int cameraId) { m_selectedCamera = cameraId; }
+    JCamera *camera() const { return m_camera; }
+
+    QCamera::State state() const { return m_state; }
+    void setState(QCamera::State state);
+
+    QCamera::Status status() const { return m_status; }
+
+    QCamera::CaptureModes captureMode() const { return m_captureMode; }
+    void setCaptureMode(QCamera::CaptureModes mode);
+    bool isCaptureModeSupported(QCamera::CaptureModes mode) const;
+
+    void setVideoPreview(QAndroidVideoOutput *videoOutput);
+    void adjustViewfinderSize(const QSize &captureSize, bool restartPreview = true);
+
+    QImageEncoderSettings imageSettings() const { return m_imageSettings; }
+    void setImageSettings(const QImageEncoderSettings &settings);
+
+    bool isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const;
+    QCameraImageCapture::CaptureDestinations captureDestination() const;
+    void setCaptureDestination(QCameraImageCapture::CaptureDestinations destination);
+
+    bool isReadyForCapture() const;
+    void setReadyForCapture(bool ready);
+    QCameraImageCapture::DriveMode driveMode() const;
+    void setDriveMode(QCameraImageCapture::DriveMode mode);
+    int capture(const QString &fileName);
+    void cancelCapture();
+
+    void onSurfaceTextureReady();
+
+    int currentCameraRotation() const;
+
+Q_SIGNALS:
+    void statusChanged(QCamera::Status status);
+    void stateChanged(QCamera::State);
+    void error(int error, const QString &errorString);
+    void captureModeChanged(QCamera::CaptureModes);
+    void opened();
+
+    void captureDestinationChanged(QCameraImageCapture::CaptureDestinations destination);
+
+    void readyForCaptureChanged(bool);
+    void imageExposed(int id);
+    void imageCaptured(int id, const QImage &preview);
+    void imageMetadataAvailable(int id, const QString &key, const QVariant &value);
+    void imageAvailable(int id, const QVideoFrame &buffer);
+    void imageSaved(int id, const QString &fileName);
+    void imageCaptureError(int id, int error, const QString &errorString);
+
+private Q_SLOTS:
+    void onApplicationStateChanged(Qt::ApplicationState state);
+
+    void onCameraPictureExposed();
+    void onCameraPictureCaptured(const QByteArray &data);
+
+private:
+    bool open();
+    void close();
+
+    void startPreview();
+    void stopPreview();
+
+    void applyImageSettings();
+    void processPreviewImage(int id);
+    void processCapturedImage(int id,
+                              const QByteArray &data,
+                              QCameraImageCapture::CaptureDestinations dest,
+                              const QString &fileName);
+
+    int m_selectedCamera;
+    JCamera *m_camera;
+    int m_nativeOrientation;
+    QAndroidVideoOutput *m_videoOutput;
+
+    QCamera::CaptureModes m_captureMode;
+    QCamera::State m_state;
+    int m_savedState;
+    QCamera::Status m_status;
+    bool m_previewStarted;
+
+    QImageEncoderSettings m_imageSettings;
+    bool m_imageSettingsDirty;
+    QCameraImageCapture::CaptureDestinations m_captureDestination;
+    QCameraImageCapture::DriveMode m_captureImageDriveMode;
+    int m_lastImageCaptureId;
+    bool m_readyForCapture;
+    bool m_captureCanceled;
+    int m_currentImageCaptureId;
+    QString m_currentImageCaptureFileName;
+
+    QAndroidMediaStorageLocation m_mediaStorageLocation;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDCAMERASESSION_H
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerazoomcontrol.cpp b/src/plugins/android/src/mediacapture/qandroidcamerazoomcontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b7030e56b32abe7197379ee5e69ecb19478fb94c
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcamerazoomcontrol.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidcamerazoomcontrol.h"
+
+#include "qandroidcamerasession.h"
+#include "jcamera.h"
+#include "qandroidmultimediautils.h"
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+QAndroidCameraZoomControl::QAndroidCameraZoomControl(QAndroidCameraSession *session)
+    : QCameraZoomControl()
+    , m_cameraSession(session)
+    , m_maximumZoom(1.0)
+    , m_requestedZoom(1.0)
+    , m_currentZoom(1.0)
+{
+    connect(m_cameraSession, SIGNAL(opened()),
+            this, SLOT(onCameraOpened()));
+}
+
+qreal QAndroidCameraZoomControl::maximumOpticalZoom() const
+{
+    // Optical zoom not supported
+    return 1.0;
+}
+
+qreal QAndroidCameraZoomControl::maximumDigitalZoom() const
+{
+    return m_maximumZoom;
+}
+
+qreal QAndroidCameraZoomControl::requestedOpticalZoom() const
+{
+    // Optical zoom not supported
+    return 1.0;
+}
+
+qreal QAndroidCameraZoomControl::requestedDigitalZoom() const
+{
+    return m_requestedZoom;
+}
+
+qreal QAndroidCameraZoomControl::currentOpticalZoom() const
+{
+    // Optical zoom not supported
+    return 1.0;
+}
+
+qreal QAndroidCameraZoomControl::currentDigitalZoom() const
+{
+    return m_currentZoom;
+}
+
+void QAndroidCameraZoomControl::zoomTo(qreal optical, qreal digital)
+{
+    Q_UNUSED(optical);
+
+    if (!m_cameraSession->camera() ||
+            qFuzzyCompare(m_requestedZoom, digital) ||
+            qFuzzyCompare(m_maximumZoom, qreal(1))) {
+        return;
+    }
+
+    m_requestedZoom = digital;
+    emit requestedDigitalZoomChanged(m_requestedZoom);
+
+    digital = qBound(qreal(1), digital, m_maximumZoom);
+    int validZoomIndex = qt_findClosestValue(m_zoomRatios, qRound(digital * 100));
+    qreal newZoom = m_zoomRatios.at(validZoomIndex) / qreal(100);
+    if (!qFuzzyCompare(m_currentZoom, newZoom)) {
+        m_cameraSession->camera()->setZoom(validZoomIndex);
+        m_currentZoom = newZoom;
+        emit currentDigitalZoomChanged(m_currentZoom);
+    }
+}
+
+void QAndroidCameraZoomControl::onCameraOpened()
+{
+    m_requestedZoom = 1.0;
+    m_currentZoom = 1.0;
+    emit requestedDigitalZoomChanged(m_requestedZoom);
+    emit currentDigitalZoomChanged(m_currentZoom);
+
+    if (m_cameraSession->camera()->isZoomSupported()) {
+        m_zoomRatios = m_cameraSession->camera()->getZoomRatios();
+        qreal maxZoom = m_zoomRatios.last() / qreal(100);
+        if (m_maximumZoom != maxZoom) {
+            m_maximumZoom = maxZoom;
+            emit maximumDigitalZoomChanged(m_maximumZoom);
+        }
+    } else {
+        m_zoomRatios.clear();
+        if (!qFuzzyCompare(m_maximumZoom, qreal(1))) {
+            m_maximumZoom = 1.0;
+            emit maximumDigitalZoomChanged(m_maximumZoom);
+        }
+    }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerazoomcontrol.h b/src/plugins/android/src/mediacapture/qandroidcamerazoomcontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..b102c5dda7e2193b3ac1e17d4bb51495c0ec6136
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcamerazoomcontrol.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDCAMERAZOOMCONTROL_H
+#define QANDROIDCAMERAZOOMCONTROL_H
+
+#include <qcamerazoomcontrol.h>
+#include <qcamera.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraSession;
+
+class QAndroidCameraZoomControl : public QCameraZoomControl
+{
+    Q_OBJECT
+public:
+    explicit QAndroidCameraZoomControl(QAndroidCameraSession *session);
+
+    qreal maximumOpticalZoom() const Q_DECL_OVERRIDE;
+    qreal maximumDigitalZoom() const Q_DECL_OVERRIDE;
+    qreal requestedOpticalZoom() const Q_DECL_OVERRIDE;
+    qreal requestedDigitalZoom() const Q_DECL_OVERRIDE;
+    qreal currentOpticalZoom() const Q_DECL_OVERRIDE;
+    qreal currentDigitalZoom() const Q_DECL_OVERRIDE;
+    void zoomTo(qreal optical, qreal digital) Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+    void onCameraOpened();
+
+private:
+    QAndroidCameraSession *m_cameraSession;
+
+    qreal m_maximumZoom;
+    QList<int> m_zoomRatios;
+    qreal m_requestedZoom;
+    qreal m_currentZoom;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDCAMERAZOOMCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp b/src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3468c64e54d33288ced24311be8a26b73169e35e
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcaptureservice.cpp
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidcaptureservice.h"
+
+#include "qandroidmediarecordercontrol.h"
+#include "qandroidcapturesession.h"
+#include "qandroidcameracontrol.h"
+#include "qandroidvideodeviceselectorcontrol.h"
+#include "qandroidaudioinputselectorcontrol.h"
+#include "qandroidcamerasession.h"
+#include "qandroidvideorendercontrol.h"
+#include "qandroidcamerazoomcontrol.h"
+#include "qandroidcameraexposurecontrol.h"
+#include "qandroidcameraflashcontrol.h"
+#include "qandroidcamerafocuscontrol.h"
+#include "qandroidcameralockscontrol.h"
+#include "qandroidcameraimageprocessingcontrol.h"
+#include "qandroidimageencodercontrol.h"
+#include "qandroidcameraimagecapturecontrol.h"
+#include "qandroidcameracapturedestinationcontrol.h"
+#include "qandroidcameracapturebufferformatcontrol.h"
+#include "qandroidaudioencodersettingscontrol.h"
+#include "qandroidvideoencodersettingscontrol.h"
+#include "qandroidmediacontainercontrol.h"
+
+#include <qmediaserviceproviderplugin.h>
+
+QT_BEGIN_NAMESPACE
+
+QAndroidCaptureService::QAndroidCaptureService(const QString &service, QObject *parent)
+    : QMediaService(parent)
+    , m_service(service)
+    , m_videoRendererControl(0)
+{
+    if (m_service == QLatin1String(Q_MEDIASERVICE_CAMERA)) {
+        m_cameraSession = new QAndroidCameraSession;
+        m_cameraControl = new QAndroidCameraControl(m_cameraSession);
+        m_videoInputControl = new QAndroidVideoDeviceSelectorControl(m_cameraSession);
+        m_cameraZoomControl = new QAndroidCameraZoomControl(m_cameraSession);
+        m_cameraExposureControl = new QAndroidCameraExposureControl(m_cameraSession);
+        m_cameraFlashControl = new QAndroidCameraFlashControl(m_cameraSession);
+        m_cameraFocusControl = new QAndroidCameraFocusControl(m_cameraSession);
+        m_cameraLocksControl = new QAndroidCameraLocksControl(m_cameraSession);
+        m_cameraImageProcessingControl = new QAndroidCameraImageProcessingControl(m_cameraSession);
+        m_imageEncoderControl = new QAndroidImageEncoderControl(m_cameraSession);
+        m_imageCaptureControl = new QAndroidCameraImageCaptureControl(m_cameraSession);
+        m_captureDestinationControl = new QAndroidCameraCaptureDestinationControl(m_cameraSession);
+        m_captureBufferFormatControl = new QAndroidCameraCaptureBufferFormatControl;
+        m_audioInputControl = 0;
+    } else {
+        m_cameraSession = 0;
+        m_cameraControl = 0;
+        m_videoInputControl = 0;
+        m_cameraZoomControl = 0;
+        m_cameraExposureControl = 0;
+        m_cameraFlashControl = 0;
+        m_cameraFocusControl = 0;
+        m_cameraLocksControl = 0;
+        m_cameraImageProcessingControl = 0;
+        m_imageEncoderControl = 0;
+        m_imageCaptureControl = 0;
+        m_captureDestinationControl = 0;
+        m_captureBufferFormatControl = 0;
+        m_videoEncoderSettingsControl = 0;
+    }
+
+    m_captureSession = new QAndroidCaptureSession(m_cameraSession);
+    m_recorderControl = new QAndroidMediaRecorderControl(m_captureSession);
+    m_audioEncoderSettingsControl = new QAndroidAudioEncoderSettingsControl(m_captureSession);
+    m_mediaContainerControl = new QAndroidMediaContainerControl(m_captureSession);
+
+    if (m_service == QLatin1String(Q_MEDIASERVICE_CAMERA)) {
+        m_videoEncoderSettingsControl = new QAndroidVideoEncoderSettingsControl(m_captureSession);
+    } else {
+        m_audioInputControl = new QAndroidAudioInputSelectorControl(m_captureSession);
+        m_captureSession->setAudioInput(m_audioInputControl->defaultInput());
+    }
+}
+
+QAndroidCaptureService::~QAndroidCaptureService()
+{
+    delete m_audioEncoderSettingsControl;
+    delete m_videoEncoderSettingsControl;
+    delete m_mediaContainerControl;
+    delete m_recorderControl;
+    delete m_captureSession;
+    delete m_cameraControl;
+    delete m_audioInputControl;
+    delete m_videoInputControl;
+    delete m_videoRendererControl;
+    delete m_cameraZoomControl;
+    delete m_cameraExposureControl;
+    delete m_cameraFlashControl;
+    delete m_cameraFocusControl;
+    delete m_cameraLocksControl;
+    delete m_cameraImageProcessingControl;
+    delete m_imageEncoderControl;
+    delete m_imageCaptureControl;
+    delete m_captureDestinationControl;
+    delete m_captureBufferFormatControl;
+    delete m_cameraSession;
+}
+
+QMediaControl *QAndroidCaptureService::requestControl(const char *name)
+{
+    if (qstrcmp(name, QMediaRecorderControl_iid) == 0)
+        return m_recorderControl;
+
+    if (qstrcmp(name, QMediaContainerControl_iid) == 0)
+        return m_mediaContainerControl;
+
+    if (qstrcmp(name, QAudioEncoderSettingsControl_iid) == 0)
+        return m_audioEncoderSettingsControl;
+
+    if (qstrcmp(name, QVideoEncoderSettingsControl_iid) == 0)
+        return m_videoEncoderSettingsControl;
+
+    if (qstrcmp(name, QCameraControl_iid) == 0)
+        return m_cameraControl;
+
+    if (qstrcmp(name, QAudioInputSelectorControl_iid) == 0)
+        return m_audioInputControl;
+
+    if (qstrcmp(name, QVideoDeviceSelectorControl_iid) == 0)
+        return m_videoInputControl;
+
+    if (qstrcmp(name, QCameraZoomControl_iid) == 0)
+        return m_cameraZoomControl;
+
+    if (qstrcmp(name, QCameraExposureControl_iid) == 0)
+        return m_cameraExposureControl;
+
+    if (qstrcmp(name, QCameraFlashControl_iid) == 0)
+        return m_cameraFlashControl;
+
+    if (qstrcmp(name, QCameraFocusControl_iid) == 0)
+        return m_cameraFocusControl;
+
+    if (qstrcmp(name, QCameraLocksControl_iid) == 0)
+        return m_cameraLocksControl;
+
+    if (qstrcmp(name, QCameraImageProcessingControl_iid) == 0)
+        return m_cameraImageProcessingControl;
+
+    if (qstrcmp(name, QImageEncoderControl_iid) == 0)
+        return m_imageEncoderControl;
+
+    if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0)
+        return m_imageCaptureControl;
+
+    if (qstrcmp(name, QCameraCaptureDestinationControl_iid) == 0)
+        return m_captureDestinationControl;
+
+    if (qstrcmp(name, QCameraCaptureBufferFormatControl_iid) == 0)
+        return m_captureBufferFormatControl;
+
+    if (qstrcmp(name, QVideoRendererControl_iid) == 0
+            && m_service == QLatin1String(Q_MEDIASERVICE_CAMERA)
+            && !m_videoRendererControl) {
+        m_videoRendererControl = new QAndroidVideoRendererControl;
+        m_cameraSession->setVideoPreview(m_videoRendererControl);
+        return m_videoRendererControl;
+    }
+
+    return 0;
+}
+
+void QAndroidCaptureService::releaseControl(QMediaControl *control)
+{
+    if (control && control == m_videoRendererControl) {
+        m_cameraSession->setVideoPreview(0);
+        delete m_videoRendererControl;
+        m_videoRendererControl = 0;
+    }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcaptureservice.h b/src/plugins/android/src/mediacapture/qandroidcaptureservice.h
new file mode 100644
index 0000000000000000000000000000000000000000..71aaf2d6424102cfebf19ddf591cbfdffa0fc749
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcaptureservice.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDCAPTURESERVICE_H
+#define QANDROIDCAPTURESERVICE_H
+
+#include <qmediaservice.h>
+#include <qmediacontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidMediaRecorderControl;
+class QAndroidCaptureSession;
+class QAndroidCameraControl;
+class QAndroidVideoDeviceSelectorControl;
+class QAndroidAudioInputSelectorControl;
+class QAndroidCameraSession;
+class QAndroidVideoRendererControl;
+class QAndroidCameraZoomControl;
+class QAndroidCameraExposureControl;
+class QAndroidCameraFlashControl;
+class QAndroidCameraFocusControl;
+class QAndroidCameraLocksControl;
+class QAndroidCameraImageProcessingControl;
+class QAndroidImageEncoderControl;
+class QAndroidCameraImageCaptureControl;
+class QAndroidCameraCaptureDestinationControl;
+class QAndroidCameraCaptureBufferFormatControl;
+class QAndroidAudioEncoderSettingsControl;
+class QAndroidVideoEncoderSettingsControl;
+class QAndroidMediaContainerControl;
+
+class QAndroidCaptureService : public QMediaService
+{
+    Q_OBJECT
+
+public:
+    explicit QAndroidCaptureService(const QString &service, QObject *parent = 0);
+    virtual ~QAndroidCaptureService();
+
+    QMediaControl *requestControl(const char *name);
+    void releaseControl(QMediaControl *);
+
+private:
+    QString m_service;
+
+    QAndroidMediaRecorderControl *m_recorderControl;
+    QAndroidCaptureSession *m_captureSession;
+    QAndroidCameraControl *m_cameraControl;
+    QAndroidVideoDeviceSelectorControl *m_videoInputControl;
+    QAndroidAudioInputSelectorControl *m_audioInputControl;
+    QAndroidCameraSession *m_cameraSession;
+    QAndroidVideoRendererControl *m_videoRendererControl;
+    QAndroidCameraZoomControl *m_cameraZoomControl;
+    QAndroidCameraExposureControl *m_cameraExposureControl;
+    QAndroidCameraFlashControl *m_cameraFlashControl;
+    QAndroidCameraFocusControl *m_cameraFocusControl;
+    QAndroidCameraLocksControl *m_cameraLocksControl;
+    QAndroidCameraImageProcessingControl *m_cameraImageProcessingControl;
+    QAndroidImageEncoderControl *m_imageEncoderControl;
+    QAndroidCameraImageCaptureControl *m_imageCaptureControl;
+    QAndroidCameraCaptureDestinationControl *m_captureDestinationControl;
+    QAndroidCameraCaptureBufferFormatControl *m_captureBufferFormatControl;
+    QAndroidAudioEncoderSettingsControl *m_audioEncoderSettingsControl;
+    QAndroidVideoEncoderSettingsControl *m_videoEncoderSettingsControl;
+    QAndroidMediaContainerControl *m_mediaContainerControl;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDCAPTURESERVICE_H
diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1927aeb8ea50911cc75beb88b2c916ee446f2fb4
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
@@ -0,0 +1,547 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidcapturesession.h"
+
+#include "jcamera.h"
+#include "qandroidcamerasession.h"
+#include "jmultimediautils.h"
+#include "qandroidmultimediautils.h"
+#include <QtPlatformSupport/private/qjnihelpers_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QAndroidCaptureSession::QAndroidCaptureSession(QAndroidCameraSession *cameraSession)
+    : QObject()
+    , m_mediaRecorder(0)
+    , m_cameraSession(cameraSession)
+    , m_audioSource(JMediaRecorder::DefaultAudioSource)
+    , m_duration(0)
+    , m_state(QMediaRecorder::StoppedState)
+    , m_status(QMediaRecorder::UnloadedStatus)
+    , m_resolutionDirty(false)
+    , m_containerFormatDirty(true)
+    , m_videoSettingsDirty(true)
+    , m_audioSettingsDirty(true)
+    , m_outputFormat(JMediaRecorder::DefaultOutputFormat)
+    , m_audioEncoder(JMediaRecorder::DefaultAudioEncoder)
+    , m_videoEncoder(JMediaRecorder::DefaultVideoEncoder)
+{
+    if (cameraSession) {
+        connect(cameraSession, SIGNAL(opened()), this, SLOT(onCameraOpened()));
+        connect(cameraSession, SIGNAL(statusChanged(QCamera::Status)),
+                this, SLOT(onCameraStatusChanged(QCamera::Status)));
+        connect(cameraSession, SIGNAL(captureModeChanged(QCamera::CaptureModes)),
+                this, SLOT(onCameraCaptureModeChanged(QCamera::CaptureModes)));
+    }
+
+    m_notifyTimer.setInterval(1000);
+    connect(&m_notifyTimer, SIGNAL(timeout()), this, SLOT(updateDuration()));
+}
+
+QAndroidCaptureSession::~QAndroidCaptureSession()
+{
+    stop();
+    delete m_mediaRecorder;
+}
+
+void QAndroidCaptureSession::setAudioInput(const QString &input)
+{
+    if (m_audioInput == input)
+        return;
+
+    m_audioInput = input;
+
+    if (m_audioInput == QLatin1String("default"))
+        m_audioSource = JMediaRecorder::DefaultAudioSource;
+    else if (m_audioInput == QLatin1String("mic"))
+        m_audioSource = JMediaRecorder::Mic;
+    else if (m_audioInput == QLatin1String("voice_uplink"))
+        m_audioSource = JMediaRecorder::VoiceUplink;
+    else if (m_audioInput == QLatin1String("voice_downlink"))
+        m_audioSource = JMediaRecorder::VoiceDownlink;
+    else if (m_audioInput == QLatin1String("voice_call"))
+        m_audioSource = JMediaRecorder::VoiceCall;
+    else if (m_audioInput == QLatin1String("voice_recognition"))
+        m_audioSource = JMediaRecorder::VoiceRecognition;
+    else
+        m_audioSource = JMediaRecorder::DefaultAudioSource;
+
+    emit audioInputChanged(m_audioInput);
+}
+
+QUrl QAndroidCaptureSession::outputLocation() const
+{
+    return m_outputLocation;
+}
+
+bool QAndroidCaptureSession::setOutputLocation(const QUrl &location)
+{
+    if (m_outputLocation == location)
+        return false;
+
+    m_outputLocation = location;
+
+    if (m_outputLocation.isEmpty())
+        return true;
+
+    if (m_outputLocation.isValid() && (m_outputLocation.isLocalFile() || m_outputLocation.isRelative())) {
+        emit actualLocationChanged(m_outputLocation);
+        return true;
+    }
+
+    m_outputLocation = QUrl();
+    return false;
+}
+
+QMediaRecorder::State QAndroidCaptureSession::state() const
+{
+    return m_state;
+}
+
+void QAndroidCaptureSession::setState(QMediaRecorder::State state)
+{
+    if (m_state == state)
+        return;
+
+    switch (state) {
+    case QMediaRecorder::StoppedState:
+        stop();
+        break;
+    case QMediaRecorder::RecordingState:
+        if (!start())
+            return;
+        break;
+    case QMediaRecorder::PausedState:
+        // Not supported by Android API
+        qWarning("QMediaRecorder::PausedState is not supported on Android");
+        return;
+    }
+
+    m_state = state;
+    emit stateChanged(m_state);
+}
+
+bool QAndroidCaptureSession::start()
+{
+    if (m_state == QMediaRecorder::RecordingState)
+        return false;
+
+    setStatus(QMediaRecorder::LoadingStatus);
+
+    if (m_mediaRecorder) {
+        m_mediaRecorder->release();
+        delete m_mediaRecorder;
+    }
+    m_mediaRecorder = new JMediaRecorder;
+    connect(m_mediaRecorder, SIGNAL(error(int,int)), this, SLOT(onError(int,int)));
+    connect(m_mediaRecorder, SIGNAL(info(int,int)), this, SLOT(onInfo(int,int)));
+
+    // Set audio/video sources
+    if (m_cameraSession) {
+        if (m_cameraSession->status() != QCamera::ActiveStatus) {
+            emit error(QMediaRecorder::ResourceError, QLatin1String("Camera must be active to record it."));
+            setStatus(QMediaRecorder::UnloadedStatus);
+            return false;
+        } else {
+            updateViewfinder();
+            m_cameraSession->camera()->unlock();
+            m_mediaRecorder->setCamera(m_cameraSession->camera());
+            m_mediaRecorder->setAudioSource(JMediaRecorder::Camcorder);
+            m_mediaRecorder->setVideoSource(JMediaRecorder::Camera);
+        }
+    } else {
+        m_mediaRecorder->setAudioSource(m_audioSource);
+    }
+
+    // Set output format
+    m_mediaRecorder->setOutputFormat(m_outputFormat);
+
+    // Set audio encoder settings
+    m_mediaRecorder->setAudioChannels(m_audioSettings.channelCount());
+    m_mediaRecorder->setAudioEncodingBitRate(m_audioSettings.bitRate());
+    m_mediaRecorder->setAudioSamplingRate(m_audioSettings.sampleRate());
+    m_mediaRecorder->setAudioEncoder(m_audioEncoder);
+
+    // Set video encoder settings
+    if (m_cameraSession) {
+        m_mediaRecorder->setVideoSize(m_videoSettings.resolution());
+        m_mediaRecorder->setVideoFrameRate(qRound(m_videoSettings.frameRate()));
+        m_mediaRecorder->setVideoEncodingBitRate(m_videoSettings.bitRate());
+        m_mediaRecorder->setVideoEncoder(m_videoEncoder);
+
+        m_mediaRecorder->setOrientationHint(m_cameraSession->currentCameraRotation());
+    }
+
+
+    // Set output file
+    QString filePath = m_mediaStorageLocation.generateFileName(m_outputLocation.isLocalFile() ? m_outputLocation.toLocalFile()
+                                                                                              : m_outputLocation.toString(),
+                                                               m_cameraSession ? QAndroidMediaStorageLocation::Camera
+                                                                               : QAndroidMediaStorageLocation::Audio,
+                                                               m_cameraSession ? QLatin1String("VID_")
+                                                                               : QLatin1String("REC_"),
+                                                               m_containerFormat);
+    m_outputLocation = QUrl::fromLocalFile(filePath);
+    emit actualLocationChanged(m_outputLocation);
+
+    m_mediaRecorder->setOutputFile(filePath);
+
+    if (!m_mediaRecorder->prepare()) {
+        emit error(QMediaRecorder::FormatError, QLatin1String("Unable to prepare the media recorder."));
+        setStatus(QMediaRecorder::UnloadedStatus);
+        return false;
+    }
+
+    setStatus(QMediaRecorder::LoadedStatus);
+    setStatus(QMediaRecorder::StartingStatus);
+
+    if (!m_mediaRecorder->start()) {
+        emit error(QMediaRecorder::FormatError, QLatin1String("Unable to start the media recorder."));
+        setStatus(QMediaRecorder::UnloadedStatus);
+        return false;
+    }
+
+    setStatus(QMediaRecorder::RecordingStatus);
+
+    m_elapsedTime.start();
+    m_notifyTimer.start();
+    updateDuration();
+
+    if (m_cameraSession)
+        m_cameraSession->setReadyForCapture(false);
+
+    return true;
+}
+
+void QAndroidCaptureSession::stop(bool error)
+{
+    if (m_state == QMediaRecorder::StoppedState)
+        return;
+
+    setStatus(QMediaRecorder::FinalizingStatus);
+
+    m_mediaRecorder->stop();
+
+    m_notifyTimer.stop();
+    updateDuration();
+    m_elapsedTime.invalidate();
+
+    if (m_cameraSession) {
+        m_cameraSession->camera()->reconnect();
+        // Viewport needs to be restarted
+        m_cameraSession->camera()->startPreview();
+        m_cameraSession->setReadyForCapture(true);
+    }
+
+    m_mediaRecorder->release();
+    delete m_mediaRecorder;
+    m_mediaRecorder = 0;
+
+    if (!error) {
+        // if the media is saved into the standard media location, register it
+        // with the Android media scanner so it appears immediately in apps
+        // such as the gallery.
+        QString mediaPath = m_outputLocation.toLocalFile();
+        QString standardLoc = m_cameraSession ? JMultimediaUtils::getDefaultMediaDirectory(JMultimediaUtils::DCIM)
+                                              : JMultimediaUtils::getDefaultMediaDirectory(JMultimediaUtils::Sounds);
+        if (mediaPath.startsWith(standardLoc))
+            JMultimediaUtils::registerMediaFile(mediaPath);
+    }
+
+    setStatus(QMediaRecorder::UnloadedStatus);
+}
+
+void QAndroidCaptureSession::setStatus(QMediaRecorder::Status status)
+{
+    if (m_status == status)
+        return;
+
+    m_status = status;
+    emit statusChanged(m_status);
+}
+
+QMediaRecorder::Status QAndroidCaptureSession::status() const
+{
+    return m_status;
+}
+
+qint64 QAndroidCaptureSession::duration() const
+{
+    return m_duration;
+}
+
+void QAndroidCaptureSession::setContainerFormat(const QString &format)
+{
+    if (m_containerFormat == format)
+        return;
+
+    m_containerFormat = format;
+    m_containerFormatDirty = true;
+}
+
+void QAndroidCaptureSession::setAudioSettings(const QAudioEncoderSettings &settings)
+{
+    if (m_audioSettings == settings)
+        return;
+
+    m_audioSettings = settings;
+    m_audioSettingsDirty = true;
+}
+
+void QAndroidCaptureSession::setVideoSettings(const QVideoEncoderSettings &settings)
+{
+    if (!m_cameraSession || m_videoSettings == settings)
+        return;
+
+    if (m_videoSettings.resolution() != settings.resolution())
+        m_resolutionDirty = true;
+
+    m_videoSettings = settings;
+    m_videoSettingsDirty = true;
+}
+
+void QAndroidCaptureSession::applySettings()
+{
+    // container settings
+    if (m_containerFormatDirty) {
+        if (m_containerFormat.isEmpty()) {
+            m_containerFormat = m_defaultSettings.outputFileExtension;
+            m_outputFormat = m_defaultSettings.outputFormat;
+        } else if (m_containerFormat == QLatin1String("3gp")) {
+            m_outputFormat = JMediaRecorder::THREE_GPP;
+        } else if (!m_cameraSession && m_containerFormat == QLatin1String("amr")) {
+            m_outputFormat = JMediaRecorder::AMR_NB_Format;
+        } else if (!m_cameraSession && m_containerFormat == QLatin1String("awb")) {
+            m_outputFormat = JMediaRecorder::AMR_WB_Format;
+        } else {
+            m_containerFormat = QStringLiteral("mp4");
+            m_outputFormat = JMediaRecorder::MPEG_4;
+        }
+
+        m_containerFormatDirty = false;
+    }
+
+    // audio settings
+    if (m_audioSettingsDirty) {
+        if (m_audioSettings.channelCount() <= 0)
+            m_audioSettings.setChannelCount(m_defaultSettings.audioChannels);
+        if (m_audioSettings.bitRate() <= 0)
+            m_audioSettings.setBitRate(m_defaultSettings.audioBitRate);
+        if (m_audioSettings.sampleRate() <= 0)
+            m_audioSettings.setSampleRate(m_defaultSettings.audioSampleRate);
+
+        if (m_audioSettings.codec().isEmpty())
+            m_audioEncoder = m_defaultSettings.audioEncoder;
+        else if (m_audioSettings.codec() == QLatin1String("aac"))
+            m_audioEncoder = JMediaRecorder::AAC;
+        else if (m_audioSettings.codec() == QLatin1String("amr-nb"))
+            m_audioEncoder = JMediaRecorder::AMR_NB_Encoder;
+        else if (m_audioSettings.codec() == QLatin1String("amr-wb"))
+            m_audioEncoder = JMediaRecorder::AMR_WB_Encoder;
+        else
+            m_audioEncoder = m_defaultSettings.audioEncoder;
+
+        m_audioSettingsDirty = false;
+    }
+
+    // video settings
+    if (m_cameraSession && m_videoSettingsDirty) {
+        if (m_videoSettings.resolution().isEmpty()) {
+            m_videoSettings.setResolution(m_defaultSettings.videoResolution);
+            m_resolutionDirty = true;
+        } else if (!m_supportedResolutions.contains(m_videoSettings.resolution())) {
+            // if the requested resolution is not supported, find the closest one
+            QSize reqSize = m_videoSettings.resolution();
+            int reqPixelCount = reqSize.width() * reqSize.height();
+            QList<int> supportedPixelCounts;
+            for (int i = 0; i < m_supportedResolutions.size(); ++i) {
+                const QSize &s = m_supportedResolutions.at(i);
+                supportedPixelCounts.append(s.width() * s.height());
+            }
+            int closestIndex = qt_findClosestValue(supportedPixelCounts, reqPixelCount);
+            m_videoSettings.setResolution(m_supportedResolutions.at(closestIndex));
+            m_resolutionDirty = true;
+        }
+
+        if (m_videoSettings.frameRate() <= 0)
+            m_videoSettings.setFrameRate(m_defaultSettings.videoFrameRate);
+        if (m_videoSettings.bitRate() <= 0)
+            m_videoSettings.setBitRate(m_defaultSettings.videoBitRate);
+
+        if (m_videoSettings.codec().isEmpty())
+            m_videoEncoder = m_defaultSettings.videoEncoder;
+        else if (m_videoSettings.codec() == QLatin1String("h263"))
+            m_videoEncoder = JMediaRecorder::H263;
+        else if (m_videoSettings.codec() == QLatin1String("h264"))
+            m_videoEncoder = JMediaRecorder::H264;
+        else if (m_videoSettings.codec() == QLatin1String("mpeg4_sp"))
+            m_videoEncoder = JMediaRecorder::MPEG_4_SP;
+        else
+            m_videoEncoder = m_defaultSettings.videoEncoder;
+
+        m_videoSettingsDirty = false;
+    }
+}
+
+void QAndroidCaptureSession::updateViewfinder()
+{
+    if (!m_resolutionDirty)
+        return;
+
+    m_cameraSession->camera()->stopPreview();
+    m_cameraSession->adjustViewfinderSize(m_videoSettings.resolution(), false);
+    m_resolutionDirty = false;
+}
+
+void QAndroidCaptureSession::updateDuration()
+{
+    if (m_elapsedTime.isValid())
+        m_duration = m_elapsedTime.elapsed();
+
+    emit durationChanged(m_duration);
+}
+
+void QAndroidCaptureSession::onCameraOpened()
+{
+    m_supportedResolutions.clear();
+    m_supportedFramerates.clear();
+
+    // get supported resolutions from predefined profiles
+    for (int i = 0; i < 8; ++i) {
+        CaptureProfile profile = getProfile(i);
+        if (!profile.isNull) {
+            if (i == 1) // QUALITY_HIGH
+                m_defaultSettings = profile;
+
+            if (!m_supportedResolutions.contains(profile.videoResolution))
+                m_supportedResolutions.append(profile.videoResolution);
+            if (!m_supportedFramerates.contains(profile.videoFrameRate))
+                m_supportedFramerates.append(profile.videoFrameRate);
+        }
+    }
+
+    qSort(m_supportedResolutions.begin(), m_supportedResolutions.end(), qt_sizeLessThan);
+    qSort(m_supportedFramerates.begin(), m_supportedFramerates.end());
+}
+
+QAndroidCaptureSession::CaptureProfile QAndroidCaptureSession::getProfile(int id)
+{
+    CaptureProfile profile;
+    bool hasProfile = QJNIObject::callStaticMethod<jboolean>("android/media/CamcorderProfile",
+                                                             "hasProfile",
+                                                             "(II)Z",
+                                                             m_cameraSession->camera()->cameraId(),
+                                                             id);
+
+    if (hasProfile) {
+        QJNILocalRef<jobject> ref = QJNIObject::callStaticObjectMethod<jobject>("android/media/CamcorderProfile",
+                                                                                "get",
+                                                                                "(II)Landroid/media/CamcorderProfile;",
+                                                                                m_cameraSession->camera()->cameraId(),
+                                                                                id);
+
+
+        QJNIObject obj(ref.object());
+
+        profile.outputFormat = JMediaRecorder::OutputFormat(obj.getField<jint>("fileFormat"));
+        profile.audioEncoder = JMediaRecorder::AudioEncoder(obj.getField<jint>("audioCodec"));
+        profile.audioBitRate = obj.getField<jint>("audioBitRate");
+        profile.audioChannels = obj.getField<jint>("audioChannels");
+        profile.audioSampleRate = obj.getField<jint>("audioSampleRate");
+        profile.videoEncoder = JMediaRecorder::VideoEncoder(obj.getField<jint>("videoCodec"));
+        profile.videoBitRate = obj.getField<jint>("videoBitRate");
+        profile.videoFrameRate = obj.getField<jint>("videoFrameRate");
+        profile.videoResolution = QSize(obj.getField<jint>("videoFrameWidth"),
+                                        obj.getField<jint>("videoFrameHeight"));
+
+        if (profile.outputFormat == JMediaRecorder::MPEG_4)
+            profile.outputFileExtension = QStringLiteral("mp4");
+        else if (profile.outputFormat == JMediaRecorder::THREE_GPP)
+            profile.outputFileExtension = QStringLiteral("3gp");
+        else if (profile.outputFormat == JMediaRecorder::AMR_NB_Format)
+            profile.outputFileExtension = QStringLiteral("amr");
+        else if (profile.outputFormat == JMediaRecorder::AMR_WB_Format)
+            profile.outputFileExtension = QStringLiteral("awb");
+
+        profile.isNull = false;
+    }
+
+    return profile;
+}
+
+void QAndroidCaptureSession::onCameraStatusChanged(QCamera::Status status)
+{
+    if (status == QCamera::StoppingStatus)
+        setState(QMediaRecorder::StoppedState);
+}
+
+void QAndroidCaptureSession::onCameraCaptureModeChanged(QCamera::CaptureModes mode)
+{
+    if (!mode.testFlag(QCamera::CaptureVideo))
+        setState(QMediaRecorder::StoppedState);
+}
+
+void QAndroidCaptureSession::onError(int what, int extra)
+{
+    Q_UNUSED(what)
+    Q_UNUSED(extra)
+    stop(true);
+    m_state = QMediaRecorder::StoppedState;
+    emit stateChanged(m_state);
+    emit error(QMediaRecorder::ResourceError, QLatin1String("Unknown error."));
+}
+
+void QAndroidCaptureSession::onInfo(int what, int extra)
+{
+    Q_UNUSED(extra)
+    if (what == 800) {
+        // MEDIA_RECORDER_INFO_MAX_DURATION_REACHED
+        setState(QMediaRecorder::StoppedState);
+        emit error(QMediaRecorder::OutOfSpaceError, QLatin1String("Maximum duration reached."));
+    } else if (what == 801) {
+        // MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED
+        setState(QMediaRecorder::StoppedState);
+        emit error(QMediaRecorder::OutOfSpaceError, QLatin1String("Maximum file size reached."));
+    }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.h b/src/plugins/android/src/mediacapture/qandroidcapturesession.h
new file mode 100644
index 0000000000000000000000000000000000000000..6d3645c13b4de51b926a48317317f145634a35ce
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.h
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDCAPTURESESSION_H
+#define QANDROIDCAPTURESESSION_H
+
+#include <qobject.h>
+#include <qmediarecorder.h>
+#include <qurl.h>
+#include <qelapsedtimer.h>
+#include <qtimer.h>
+#include "qandroidmediastoragelocation.h"
+#include "jmediarecorder.h"
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraSession;
+
+class QAndroidCaptureSession : public QObject
+{
+    Q_OBJECT
+public:
+    explicit QAndroidCaptureSession(QAndroidCameraSession *cameraSession = 0);
+    ~QAndroidCaptureSession();
+
+    QList<QSize> supportedResolutions() const { return m_supportedResolutions; }
+    QList<qreal> supportedFrameRates() const { return m_supportedFramerates; }
+
+    QString audioInput() const { return m_audioInput; }
+    void setAudioInput(const QString &input);
+
+    QUrl outputLocation() const;
+    bool setOutputLocation(const QUrl &location);
+
+    QMediaRecorder::State state() const;
+    void setState(QMediaRecorder::State state);
+
+    QMediaRecorder::Status status() const;
+
+    qint64 duration() const;
+
+    QString containerFormat() const { return m_containerFormat; }
+    void setContainerFormat(const QString &format);
+
+    QAudioEncoderSettings audioSettings() const { return m_audioSettings; }
+    void setAudioSettings(const QAudioEncoderSettings &settings);
+
+    QVideoEncoderSettings videoSettings() const { return m_videoSettings; }
+    void setVideoSettings(const QVideoEncoderSettings &settings);
+
+    void applySettings();
+
+Q_SIGNALS:
+    void audioInputChanged(const QString& name);
+    void stateChanged(QMediaRecorder::State state);
+    void statusChanged(QMediaRecorder::Status status);
+    void durationChanged(qint64 position);
+    void actualLocationChanged(const QUrl &location);
+    void error(int error, const QString &errorString);
+
+private Q_SLOTS:
+    void updateDuration();
+    void onCameraOpened();
+    void onCameraStatusChanged(QCamera::Status);
+    void onCameraCaptureModeChanged(QCamera::CaptureModes mode);
+
+    void onError(int what, int extra);
+    void onInfo(int what, int extra);
+
+private:
+    struct CaptureProfile {
+        JMediaRecorder::OutputFormat outputFormat;
+        QString outputFileExtension;
+
+        JMediaRecorder::AudioEncoder audioEncoder;
+        int audioBitRate;
+        int audioChannels;
+        int audioSampleRate;
+
+        JMediaRecorder::VideoEncoder videoEncoder;
+        int videoBitRate;
+        int videoFrameRate;
+        QSize videoResolution;
+
+        bool isNull;
+
+        CaptureProfile()
+            : outputFormat(JMediaRecorder::MPEG_4)
+            , outputFileExtension(QLatin1String("mp4"))
+            , audioEncoder(JMediaRecorder::DefaultAudioEncoder)
+            , audioBitRate(128000)
+            , audioChannels(2)
+            , audioSampleRate(44100)
+            , videoEncoder(JMediaRecorder::DefaultVideoEncoder)
+            , videoBitRate(1)
+            , videoFrameRate(-1)
+            , videoResolution(320, 240)
+            , isNull(true)
+        { }
+    };
+
+    CaptureProfile getProfile(int id);
+
+    bool start();
+    void stop(bool error = false);
+
+    void setStatus(QMediaRecorder::Status status);
+
+    void updateViewfinder();
+
+    JMediaRecorder *m_mediaRecorder;
+    QAndroidCameraSession *m_cameraSession;
+
+    QString m_audioInput;
+    JMediaRecorder::AudioSource m_audioSource;
+
+    QAndroidMediaStorageLocation m_mediaStorageLocation;
+
+    QElapsedTimer m_elapsedTime;
+    QTimer m_notifyTimer;
+    qint64 m_duration;
+
+    QMediaRecorder::State m_state;
+    QMediaRecorder::Status m_status;
+    QUrl m_outputLocation;
+
+    CaptureProfile m_defaultSettings;
+
+    QString m_containerFormat;
+    QAudioEncoderSettings m_audioSettings;
+    QVideoEncoderSettings m_videoSettings;
+    bool m_resolutionDirty;
+    bool m_containerFormatDirty;
+    bool m_videoSettingsDirty;
+    bool m_audioSettingsDirty;
+    JMediaRecorder::OutputFormat m_outputFormat;
+    JMediaRecorder::AudioEncoder m_audioEncoder;
+    JMediaRecorder::VideoEncoder m_videoEncoder;
+
+    QList<QSize> m_supportedResolutions;
+    QList<qreal> m_supportedFramerates;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDCAPTURESESSION_H
diff --git a/src/plugins/android/src/mediacapture/qandroidimageencodercontrol.cpp b/src/plugins/android/src/mediacapture/qandroidimageencodercontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..79e0651a385bf725b4c42d2628a67fa2cba1e74e
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidimageencodercontrol.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidimageencodercontrol.h"
+
+#include "qandroidcamerasession.h"
+#include "jcamera.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidImageEncoderControl::QAndroidImageEncoderControl(QAndroidCameraSession *session)
+    : QImageEncoderControl()
+    , m_session(session)
+{
+    connect(m_session, SIGNAL(opened()),
+            this, SLOT(onCameraOpened()));
+}
+
+QStringList QAndroidImageEncoderControl::supportedImageCodecs() const
+{
+    return QStringList() << QLatin1String("jpeg");
+}
+
+QString QAndroidImageEncoderControl::imageCodecDescription(const QString &codecName) const
+{
+    if (codecName == QLatin1String("jpeg"))
+        return tr("JPEG image");
+
+    return QString();
+}
+
+QList<QSize> QAndroidImageEncoderControl::supportedResolutions(const QImageEncoderSettings &settings, bool *continuous) const
+{
+    Q_UNUSED(settings);
+
+    if (continuous)
+        *continuous = false;
+
+    return m_supportedResolutions;
+}
+
+QImageEncoderSettings QAndroidImageEncoderControl::imageSettings() const
+{
+    return m_session->imageSettings();
+}
+
+void QAndroidImageEncoderControl::setImageSettings(const QImageEncoderSettings &settings)
+{
+    m_session->setImageSettings(settings);
+}
+
+void QAndroidImageEncoderControl::onCameraOpened()
+{
+    m_supportedResolutions = m_session->camera()->getSupportedPictureSizes();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidimageencodercontrol.h b/src/plugins/android/src/mediacapture/qandroidimageencodercontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..23e397d4d20b91baf3f6d41dbb620cbd20fad3d1
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidimageencodercontrol.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDIMAGEENCODERCONTROL_H
+#define QANDROIDIMAGEENCODERCONTROL_H
+
+#include <qimageencodercontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraSession;
+
+class QAndroidImageEncoderControl : public QImageEncoderControl
+{
+    Q_OBJECT
+public:
+    explicit QAndroidImageEncoderControl(QAndroidCameraSession *session);
+
+    QStringList supportedImageCodecs() const Q_DECL_OVERRIDE;
+    QString imageCodecDescription(const QString &codecName) const Q_DECL_OVERRIDE;
+    QList<QSize> supportedResolutions(const QImageEncoderSettings &settings, bool *continuous = 0) const Q_DECL_OVERRIDE;
+    QImageEncoderSettings imageSettings() const Q_DECL_OVERRIDE;
+    void setImageSettings(const QImageEncoderSettings &settings) Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+    void onCameraOpened();
+
+private:
+    QAndroidCameraSession *m_session;
+
+    QList<QSize> m_supportedResolutions;
+};
+
+#endif // QANDROIDIMAGEENCODERCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidmediacontainercontrol.cpp b/src/plugins/android/src/mediacapture/qandroidmediacontainercontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..33f7f23510b6295244670d7e5bc75bcc6a824795
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidmediacontainercontrol.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidmediacontainercontrol.h"
+
+#include "qandroidcapturesession.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidMediaContainerControl::QAndroidMediaContainerControl(QAndroidCaptureSession *session)
+    : QMediaContainerControl()
+    , m_session(session)
+{
+}
+
+QStringList QAndroidMediaContainerControl::supportedContainers() const
+{
+    return QStringList() << QLatin1String("mp4")
+                         << QLatin1String("3gp")
+                         << QLatin1String("amr")
+                         << QLatin1String("awb");
+}
+
+QString QAndroidMediaContainerControl::containerFormat() const
+{
+    return m_session->containerFormat();
+}
+
+void QAndroidMediaContainerControl::setContainerFormat(const QString &format)
+{
+    m_session->setContainerFormat(format);
+}
+
+QString QAndroidMediaContainerControl::containerDescription(const QString &formatMimeType) const
+{
+    if (formatMimeType == QLatin1String("mp4"))
+        return tr("MPEG4 media file format");
+    else if (formatMimeType == QLatin1String("3gp"))
+        return tr("3GPP media file format");
+    else if (formatMimeType == QLatin1String("amr"))
+        return tr("AMR NB file format");
+    else if (formatMimeType == QLatin1String("awb"))
+        return tr("AMR WB file format");
+
+    return QString();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidmediacontainercontrol.h b/src/plugins/android/src/mediacapture/qandroidmediacontainercontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..d52e8365ff83b02765266f42257a4d5cc28d7357
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidmediacontainercontrol.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDMEDIACONTAINERCONTROL_H
+#define QANDROIDMEDIACONTAINERCONTROL_H
+
+#include <qmediacontainercontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCaptureSession;
+
+class QAndroidMediaContainerControl : public QMediaContainerControl
+{
+    Q_OBJECT
+public:
+    QAndroidMediaContainerControl(QAndroidCaptureSession *session);
+
+    QStringList supportedContainers() const Q_DECL_OVERRIDE;
+    QString containerFormat() const Q_DECL_OVERRIDE;
+    void setContainerFormat(const QString &format) Q_DECL_OVERRIDE;
+    QString containerDescription(const QString &formatMimeType) const Q_DECL_OVERRIDE;
+
+private:
+    QAndroidCaptureSession *m_session;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDMEDIACONTAINERCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidmediarecordercontrol.cpp b/src/plugins/android/src/mediacapture/qandroidmediarecordercontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dab9f3e30752103142b818fd3dc79058f9e9f259
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidmediarecordercontrol.cpp
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidmediarecordercontrol.h"
+
+#include "qandroidcapturesession.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidMediaRecorderControl::QAndroidMediaRecorderControl(QAndroidCaptureSession *session)
+    : QMediaRecorderControl()
+    , m_session(session)
+{
+    connect(m_session, SIGNAL(stateChanged(QMediaRecorder::State)), this, SIGNAL(stateChanged(QMediaRecorder::State)));
+    connect(m_session, SIGNAL(statusChanged(QMediaRecorder::Status)), this, SIGNAL(statusChanged(QMediaRecorder::Status)));
+    connect(m_session, SIGNAL(durationChanged(qint64)), this, SIGNAL(durationChanged(qint64)));
+    connect(m_session, SIGNAL(actualLocationChanged(QUrl)), this, SIGNAL(actualLocationChanged(QUrl)));
+    connect(m_session, SIGNAL(error(int,QString)), this, SIGNAL(error(int,QString)));
+}
+
+QUrl QAndroidMediaRecorderControl::outputLocation() const
+{
+    return m_session->outputLocation();
+}
+
+bool QAndroidMediaRecorderControl::setOutputLocation(const QUrl &location)
+{
+    return m_session->setOutputLocation(location);
+}
+
+QMediaRecorder::State QAndroidMediaRecorderControl::state() const
+{
+    return m_session->state();
+}
+
+QMediaRecorder::Status QAndroidMediaRecorderControl::status() const
+{
+    return m_session->status();
+}
+
+qint64 QAndroidMediaRecorderControl::duration() const
+{
+    return m_session->duration();
+}
+
+bool QAndroidMediaRecorderControl::isMuted() const
+{
+    // No API for this in Android
+    return false;
+}
+
+qreal QAndroidMediaRecorderControl::volume() const
+{
+    // No API for this in Android
+    return 1.0;
+}
+
+void QAndroidMediaRecorderControl::applySettings()
+{
+    m_session->applySettings();
+}
+
+void QAndroidMediaRecorderControl::setState(QMediaRecorder::State state)
+{
+    m_session->setState(state);
+}
+
+void QAndroidMediaRecorderControl::setMuted(bool muted)
+{
+    // No API for this in Android
+    Q_UNUSED(muted)
+    qWarning("QMediaRecorder::setMuted() is not supported on Android.");
+}
+
+void QAndroidMediaRecorderControl::setVolume(qreal volume)
+{
+    // No API for this in Android
+    Q_UNUSED(volume)
+    qWarning("QMediaRecorder::setVolume() is not supported on Android.");
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidmediarecordercontrol.h b/src/plugins/android/src/mediacapture/qandroidmediarecordercontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..c518f7f7004f666a6359276d6602866c7845f59a
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidmediarecordercontrol.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDMEDIARECORDERCONTROL_H
+#define QANDROIDMEDIARECORDERCONTROL_H
+
+#include <qmediarecordercontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCaptureSession;
+
+class QAndroidMediaRecorderControl : public QMediaRecorderControl
+{
+    Q_OBJECT
+public:
+    explicit QAndroidMediaRecorderControl(QAndroidCaptureSession *session);
+
+    QUrl outputLocation() const Q_DECL_OVERRIDE;
+    bool setOutputLocation(const QUrl &location) Q_DECL_OVERRIDE;
+    QMediaRecorder::State state() const Q_DECL_OVERRIDE;
+    QMediaRecorder::Status status() const Q_DECL_OVERRIDE;
+    qint64 duration() const Q_DECL_OVERRIDE;
+    bool isMuted() const Q_DECL_OVERRIDE;
+    qreal volume() const Q_DECL_OVERRIDE;
+    void applySettings() Q_DECL_OVERRIDE;
+
+public Q_SLOTS:
+    void setState(QMediaRecorder::State state) Q_DECL_OVERRIDE;
+    void setMuted(bool muted) Q_DECL_OVERRIDE;
+    void setVolume(qreal volume) Q_DECL_OVERRIDE;
+
+private:
+    QAndroidCaptureSession *m_session;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDMEDIARECORDERCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidmediastoragelocation.cpp b/src/plugins/android/src/mediacapture/qandroidmediastoragelocation.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ee67341589a55fd6ee4093fd50cdd3e94b6b833e
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidmediastoragelocation.cpp
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidmediastoragelocation.h"
+
+#include "jmultimediautils.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidMediaStorageLocation::QAndroidMediaStorageLocation()
+{
+}
+
+QDir QAndroidMediaStorageLocation::defaultDir(CaptureSource source) const
+{
+    QStringList dirCandidates;
+
+    if (source == Camera)
+        dirCandidates << JMultimediaUtils::getDefaultMediaDirectory(JMultimediaUtils::DCIM);
+    else
+        dirCandidates << JMultimediaUtils::getDefaultMediaDirectory(JMultimediaUtils::Sounds);
+    dirCandidates << QDir::homePath();
+    dirCandidates << QDir::currentPath();
+    dirCandidates << QDir::tempPath();
+
+    Q_FOREACH (const QString &path, dirCandidates) {
+        if (QFileInfo(path).isWritable())
+            return QDir(path);
+    }
+
+    return QDir();
+}
+
+QString QAndroidMediaStorageLocation::generateFileName(const QString &requestedName,
+                                                       CaptureSource source,
+                                                       const QString &prefix,
+                                                       const QString &extension) const
+{
+    if (requestedName.isEmpty())
+        return generateFileName(prefix, defaultDir(source), extension);
+
+    QString path = requestedName;
+
+    if (QFileInfo(path).isRelative())
+        path = defaultDir(source).absoluteFilePath(path);
+
+    if (QFileInfo(path).isDir())
+        return generateFileName(prefix, QDir(path), extension);
+
+    if (!path.endsWith(extension))
+        path.append(QString(".%1").arg(extension));
+
+    return path;
+}
+
+QString QAndroidMediaStorageLocation::generateFileName(const QString &prefix,
+                                                       const QDir &dir,
+                                                       const QString &extension) const
+{
+    QMutexLocker lock(&m_mutex);
+
+    const QString lastMediaKey = dir.absolutePath() + QLatin1Char(' ') + prefix + QLatin1Char(' ') + extension;
+    qint64 lastMediaIndex = m_lastUsedIndex.value(lastMediaKey, 0);
+
+    if (lastMediaIndex == 0) {
+        // first run, find the maximum media number during the fist capture
+        Q_FOREACH (const QString &fileName, dir.entryList(QStringList() << QString("%1*.%2").arg(prefix).arg(extension))) {
+            const qint64 mediaIndex = fileName.mid(prefix.length(), fileName.size() - prefix.length() - extension.length() - 1).toInt();
+            lastMediaIndex = qMax(lastMediaIndex, mediaIndex);
+        }
+    }
+
+    // don't just rely on cached lastMediaIndex value,
+    // someone else may create a file after camera started
+    while (true) {
+        const QString name = QString("%1%2.%3").arg(prefix)
+                                               .arg(lastMediaIndex + 1, 8, 10, QLatin1Char('0'))
+                                               .arg(extension);
+
+        const QString path = dir.absoluteFilePath(name);
+        if (!QFileInfo(path).exists()) {
+            m_lastUsedIndex[lastMediaKey] = lastMediaIndex + 1;
+            return path;
+        }
+
+        lastMediaIndex++;
+    }
+
+    return QString();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidmediastoragelocation.h b/src/plugins/android/src/mediacapture/qandroidmediastoragelocation.h
new file mode 100644
index 0000000000000000000000000000000000000000..2e63f3df519e0cff8c8df1a9fa7e2478a5f1fecf
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidmediastoragelocation.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDMEDIASTORAGELOCATION_H
+#define QANDROIDMEDIASTORAGELOCATION_H
+
+#include <QCamera>
+#include <QDir>
+#include <QHash>
+#include <QMutex>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidMediaStorageLocation
+{
+public:
+    enum CaptureSource {
+        Camera,
+        Audio
+    };
+
+    QAndroidMediaStorageLocation();
+
+    QDir defaultDir(CaptureSource source) const;
+
+    QString generateFileName(const QString &requestedName, CaptureSource source, const QString &prefix, const QString &extension) const;
+    QString generateFileName(const QString &prefix, const QDir &dir, const QString &extension) const;
+
+private:
+    mutable QHash<QString, qint64> m_lastUsedIndex;
+
+    mutable QMutex m_mutex;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDMEDIASTORAGELOCATION_H
diff --git a/src/plugins/android/src/mediacapture/qandroidvideodeviceselectorcontrol.cpp b/src/plugins/android/src/mediacapture/qandroidvideodeviceselectorcontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..26dce565eefc0d6611e1eaace7b3f87a280bdb6e
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidvideodeviceselectorcontrol.cpp
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidvideodeviceselectorcontrol.h"
+
+#include "qandroidcamerasession.h"
+#include "jcamera.h"
+#include <QtPlatformSupport/private/qjnihelpers_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QList<QByteArray> QAndroidVideoDeviceSelectorControl::m_names;
+QStringList QAndroidVideoDeviceSelectorControl::m_descriptions;
+
+QAndroidVideoDeviceSelectorControl::QAndroidVideoDeviceSelectorControl(QAndroidCameraSession *session)
+    : QVideoDeviceSelectorControl(0)
+    , m_selectedDevice(0)
+    , m_cameraSession(session)
+{
+    if (m_names.isEmpty())
+        update();
+}
+
+QAndroidVideoDeviceSelectorControl::~QAndroidVideoDeviceSelectorControl()
+{
+}
+
+int QAndroidVideoDeviceSelectorControl::deviceCount() const
+{
+    return m_names.size();
+}
+
+QString QAndroidVideoDeviceSelectorControl::deviceName(int index) const
+{
+    return m_names.at(index);
+}
+
+QString QAndroidVideoDeviceSelectorControl::deviceDescription(int index) const
+{
+    return m_descriptions.at(index);
+}
+
+int QAndroidVideoDeviceSelectorControl::defaultDevice() const
+{
+    return 0;
+}
+
+int QAndroidVideoDeviceSelectorControl::selectedDevice() const
+{
+    return m_selectedDevice;
+}
+
+void QAndroidVideoDeviceSelectorControl::setSelectedDevice(int index)
+{
+    if (index != m_selectedDevice) {
+        m_selectedDevice = index;
+        m_cameraSession->setSelectedCamera(m_selectedDevice);
+        emit selectedDeviceChanged(index);
+        emit selectedDeviceChanged(deviceName(index));
+    }
+}
+
+void QAndroidVideoDeviceSelectorControl::update()
+{
+    m_names.clear();
+    m_descriptions.clear();
+
+    QJNIObject cameraInfo("android/hardware/Camera$CameraInfo");
+    int numCameras = QJNIObject::callStaticMethod<jint>("android/hardware/Camera",
+                                                        "getNumberOfCameras");
+
+    for (int i = 0; i < numCameras; ++i) {
+        QJNIObject::callStaticMethod<void>("android/hardware/Camera",
+                                           "getCameraInfo",
+                                           "(ILandroid/hardware/Camera$CameraInfo;)V",
+                                           i, cameraInfo.object());
+
+        JCamera::CameraFacing facing = JCamera::CameraFacing(cameraInfo.getField<jint>("facing"));
+
+        switch (facing) {
+        case JCamera::CameraFacingBack:
+            m_names.append("back");
+            m_descriptions.append(QStringLiteral("Rear-facing camera"));
+            break;
+        case JCamera::CameraFacingFront:
+            m_names.append("front");
+            m_descriptions.append(QStringLiteral("Front-facing camera"));
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+QList<QByteArray> QAndroidVideoDeviceSelectorControl::availableDevices()
+{
+    if (m_names.isEmpty())
+        update();
+
+    return m_names;
+}
+
+QString QAndroidVideoDeviceSelectorControl::availableDeviceDescription(const QByteArray &device)
+{
+    int i = m_names.indexOf(device);
+    if (i != -1)
+        return m_descriptions.at(i);
+
+    return QString();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidvideodeviceselectorcontrol.h b/src/plugins/android/src/mediacapture/qandroidvideodeviceselectorcontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..3ebf83ab20367ecc9ebe88e1a5a08749f594c52b
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidvideodeviceselectorcontrol.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDVIDEODEVICESELECTORCONTROL_H
+#define QANDROIDVIDEODEVICESELECTORCONTROL_H
+
+#include <qvideodeviceselectorcontrol.h>
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCameraSession;
+
+class QAndroidVideoDeviceSelectorControl : public QVideoDeviceSelectorControl
+{
+    Q_OBJECT
+public:
+    explicit QAndroidVideoDeviceSelectorControl(QAndroidCameraSession *session);
+    ~QAndroidVideoDeviceSelectorControl();
+
+    int deviceCount() const;
+
+    QString deviceName(int index) const;
+    QString deviceDescription(int index) const;
+
+    int defaultDevice() const;
+    int selectedDevice() const;
+
+    void setSelectedDevice(int index);
+
+    static QList<QByteArray> availableDevices();
+    static QString availableDeviceDescription(const QByteArray &device);
+
+private:
+    static void update();
+
+    int m_selectedDevice;
+    static QList<QByteArray> m_names;
+    static QStringList m_descriptions;
+
+    QAndroidCameraSession *m_cameraSession;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDVIDEODEVICESELECTORCONTROL_H
diff --git a/src/plugins/android/src/mediacapture/qandroidvideoencodersettingscontrol.cpp b/src/plugins/android/src/mediacapture/qandroidvideoencodersettingscontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..20318c8bb846bdaf1500a258ae5cbeb1bbc454da
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidvideoencodersettingscontrol.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidvideoencodersettingscontrol.h"
+
+#include "qandroidcapturesession.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidVideoEncoderSettingsControl::QAndroidVideoEncoderSettingsControl(QAndroidCaptureSession *session)
+    : QVideoEncoderSettingsControl()
+    , m_session(session)
+{
+}
+
+QList<QSize> QAndroidVideoEncoderSettingsControl::supportedResolutions(const QVideoEncoderSettings &, bool *continuous) const
+{
+    if (continuous)
+        *continuous = false;
+
+    return m_session->supportedResolutions();
+}
+
+QList<qreal> QAndroidVideoEncoderSettingsControl::supportedFrameRates(const QVideoEncoderSettings &, bool *continuous) const
+{
+    if (continuous)
+        *continuous = false;
+
+    return m_session->supportedFrameRates();
+}
+
+QStringList QAndroidVideoEncoderSettingsControl::supportedVideoCodecs() const
+{
+    return QStringList() << QLatin1String("h263")
+                         << QLatin1String("h264")
+                         << QLatin1String("mpeg4_sp");
+}
+
+QString QAndroidVideoEncoderSettingsControl::videoCodecDescription(const QString &codecName) const
+{
+    if (codecName == QLatin1String("h263"))
+        return tr("H.263 compression");
+    else if (codecName == QLatin1String("h264"))
+        return tr("H.264 compression");
+    else if (codecName == QLatin1String("mpeg4_sp"))
+        return tr("MPEG-4 SP compression");
+
+    return QString();
+}
+
+QVideoEncoderSettings QAndroidVideoEncoderSettingsControl::videoSettings() const
+{
+    return m_session->videoSettings();
+}
+
+void QAndroidVideoEncoderSettingsControl::setVideoSettings(const QVideoEncoderSettings &settings)
+{
+    m_session->setVideoSettings(settings);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/mediacapture/qandroidvideoencodersettingscontrol.h b/src/plugins/android/src/mediacapture/qandroidvideoencodersettingscontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..1427924c0723083385b25323b256948a95422fba
--- /dev/null
+++ b/src/plugins/android/src/mediacapture/qandroidvideoencodersettingscontrol.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDVIDEOENCODERSETTINGSCONTROL_H
+#define QANDROIDVIDEOENCODERSETTINGSCONTROL_H
+
+#include <qvideoencodersettingscontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidCaptureSession;
+
+class QAndroidVideoEncoderSettingsControl : public QVideoEncoderSettingsControl
+{
+    Q_OBJECT
+public:
+    explicit QAndroidVideoEncoderSettingsControl(QAndroidCaptureSession *session);
+
+    QList<QSize> supportedResolutions(const QVideoEncoderSettings &settings, bool *continuous = 0) const Q_DECL_OVERRIDE;
+    QList<qreal> supportedFrameRates(const QVideoEncoderSettings &settings, bool *continuous = 0) const Q_DECL_OVERRIDE;
+    QStringList supportedVideoCodecs() const Q_DECL_OVERRIDE;
+    QString videoCodecDescription(const QString &codecName) const Q_DECL_OVERRIDE;
+    QVideoEncoderSettings videoSettings() const Q_DECL_OVERRIDE;
+    void setVideoSettings(const QVideoEncoderSettings &settings) Q_DECL_OVERRIDE;
+
+private:
+    QAndroidCaptureSession *m_session;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDVIDEOENCODERSETTINGSCONTROL_H
diff --git a/src/plugins/android/src/mediaplayer/mediaplayer.pri b/src/plugins/android/src/mediaplayer/mediaplayer.pri
new file mode 100644
index 0000000000000000000000000000000000000000..c386d996baa9e389c9f3fc39e0edb977d7ca3603
--- /dev/null
+++ b/src/plugins/android/src/mediaplayer/mediaplayer.pri
@@ -0,0 +1,11 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+    $$PWD/qandroidmediaplayercontrol.h \
+    $$PWD/qandroidmediaservice.h \
+    $$PWD/qandroidmetadatareadercontrol.h
+
+SOURCES += \
+    $$PWD/qandroidmediaplayercontrol.cpp \
+    $$PWD/qandroidmediaservice.cpp \
+    $$PWD/qandroidmetadatareadercontrol.cpp
diff --git a/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
similarity index 99%
rename from src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp
rename to src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
index 4dc56ebd98fe07e1fe471e6ef520d320a6bebd4c..753c6066274be1e1ece5da674bdef27472f283af 100644
--- a/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
@@ -81,6 +81,7 @@ QAndroidMediaPlayerControl::QAndroidMediaPlayerControl(QObject *parent)
 
 QAndroidMediaPlayerControl::~QAndroidMediaPlayerControl()
 {
+    mMediaPlayer->stop();
     mMediaPlayer->release();
     delete mMediaPlayer;
 }
diff --git a/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.h b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
similarity index 100%
rename from src/plugins/android/mediaplayer/qandroidmediaplayercontrol.h
rename to src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
diff --git a/src/plugins/android/mediaplayer/qandroidmediaservice.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp
similarity index 100%
rename from src/plugins/android/mediaplayer/qandroidmediaservice.cpp
rename to src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp
diff --git a/src/plugins/android/mediaplayer/qandroidmediaservice.h b/src/plugins/android/src/mediaplayer/qandroidmediaservice.h
similarity index 100%
rename from src/plugins/android/mediaplayer/qandroidmediaservice.h
rename to src/plugins/android/src/mediaplayer/qandroidmediaservice.h
diff --git a/src/plugins/android/mediaplayer/qandroidmetadatareadercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp
similarity index 100%
rename from src/plugins/android/mediaplayer/qandroidmetadatareadercontrol.cpp
rename to src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp
diff --git a/src/plugins/android/mediaplayer/qandroidmetadatareadercontrol.h b/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.h
similarity index 100%
rename from src/plugins/android/mediaplayer/qandroidmetadatareadercontrol.h
rename to src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.h
diff --git a/src/plugins/android/mediaplayer/qandroidmediaserviceplugin.cpp b/src/plugins/android/src/qandroidmediaserviceplugin.cpp
similarity index 66%
rename from src/plugins/android/mediaplayer/qandroidmediaserviceplugin.cpp
rename to src/plugins/android/src/qandroidmediaserviceplugin.cpp
index 3bf703413d7ec00dbd4e638f06889143f54c8191..d7a2cd29f74fa53a5b597a5abb2ffac86567fafb 100644
--- a/src/plugins/android/mediaplayer/qandroidmediaserviceplugin.cpp
+++ b/src/plugins/android/src/qandroidmediaserviceplugin.cpp
@@ -42,9 +42,15 @@
 #include "qandroidmediaserviceplugin.h"
 
 #include "qandroidmediaservice.h"
+#include "qandroidcaptureservice.h"
+#include "qandroidvideodeviceselectorcontrol.h"
+#include "qandroidaudioinputselectorcontrol.h"
 #include "jmediaplayer.h"
 #include "jsurfacetexture.h"
 #include "jsurfacetextureholder.h"
+#include "jcamera.h"
+#include "jmultimediautils.h"
+#include "jmediarecorder.h"
 #include <qdebug.h>
 
 QT_BEGIN_NAMESPACE
@@ -59,9 +65,14 @@ QAndroidMediaServicePlugin::~QAndroidMediaServicePlugin()
 
 QMediaService *QAndroidMediaServicePlugin::create(const QString &key)
 {
-    if (key == QStringLiteral(Q_MEDIASERVICE_MEDIAPLAYER))
+    if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER))
         return new QAndroidMediaService;
 
+    if (key == QLatin1String(Q_MEDIASERVICE_CAMERA)
+            || key == QLatin1String(Q_MEDIASERVICE_AUDIOSOURCE)) {
+        return new QAndroidCaptureService(key);
+    }
+
     qWarning() << "Android service plugin: unsupported key:" << key;
     return 0;
 }
@@ -74,11 +85,39 @@ void QAndroidMediaServicePlugin::release(QMediaService *service)
 QMediaServiceProviderHint::Features QAndroidMediaServicePlugin::supportedFeatures(const QByteArray &service) const
 {
     if (service == Q_MEDIASERVICE_MEDIAPLAYER)
-        return  QMediaServiceProviderHint::VideoSurface;
+        return QMediaServiceProviderHint::VideoSurface;
+
+    if (service == Q_MEDIASERVICE_CAMERA)
+        return QMediaServiceProviderHint::VideoSurface | QMediaServiceProviderHint::RecordingSupport;
+
+    if (service == Q_MEDIASERVICE_AUDIOSOURCE)
+        return QMediaServiceProviderHint::RecordingSupport;
 
     return QMediaServiceProviderHint::Features();
 }
 
+QList<QByteArray> QAndroidMediaServicePlugin::devices(const QByteArray &service) const
+{
+    if (service == Q_MEDIASERVICE_CAMERA)
+        return QAndroidVideoDeviceSelectorControl::availableDevices();
+
+    if (service == Q_MEDIASERVICE_AUDIOSOURCE)
+        return QAndroidAudioInputSelectorControl::availableDevices();
+
+    return QList<QByteArray>();
+}
+
+QString QAndroidMediaServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device)
+{
+    if (service == Q_MEDIASERVICE_CAMERA)
+        return QAndroidVideoDeviceSelectorControl::availableDeviceDescription(device);
+
+    if (service == Q_MEDIASERVICE_AUDIOSOURCE)
+        return QAndroidAudioInputSelectorControl::availableDeviceDescription(device);
+
+    return QString();
+}
+
 
 Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/)
 {
@@ -97,7 +136,10 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/)
 
     if (!JMediaPlayer::initJNI(jniEnv) ||
         !JSurfaceTexture::initJNI(jniEnv) ||
-        !JSurfaceTextureHolder::initJNI(jniEnv)) {
+        !JSurfaceTextureHolder::initJNI(jniEnv) ||
+        !JCamera::initJNI(jniEnv) ||
+        !JMultimediaUtils::initJNI(jniEnv) ||
+        !JMediaRecorder::initJNI(jniEnv)) {
         return JNI_ERR;
     }
 
diff --git a/src/plugins/android/mediaplayer/qandroidmediaserviceplugin.h b/src/plugins/android/src/qandroidmediaserviceplugin.h
similarity index 89%
rename from src/plugins/android/mediaplayer/qandroidmediaserviceplugin.h
rename to src/plugins/android/src/qandroidmediaserviceplugin.h
index d004635f2e0060ea1dfea7be00cc1f6e3d179dcc..18b1def21446a945380ff1d37baa42a118966c1b 100644
--- a/src/plugins/android/mediaplayer/qandroidmediaserviceplugin.h
+++ b/src/plugins/android/src/qandroidmediaserviceplugin.h
@@ -46,17 +46,16 @@
 
 QT_BEGIN_NAMESPACE
 
-class QMediaService;
-class QAndroidMediaService;
-
 class QAndroidMediaServicePlugin
         : public QMediaServiceProviderPlugin
+        , public QMediaServiceSupportedDevicesInterface
         , public QMediaServiceFeaturesInterface
 {
     Q_OBJECT
+    Q_INTERFACES(QMediaServiceSupportedDevicesInterface)
     Q_INTERFACES(QMediaServiceFeaturesInterface)
     Q_PLUGIN_METADATA(IID "org.qt-project.qt.mediaserviceproviderfactory/5.0"
-                      FILE "mediaplayer.json")
+                      FILE "android_mediaservice.json")
 
 public:
     QAndroidMediaServicePlugin();
@@ -64,7 +63,11 @@ public:
 
     QMediaService* create(QString const& key) Q_DECL_OVERRIDE;
     void release(QMediaService *service) Q_DECL_OVERRIDE;
+
     QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const Q_DECL_OVERRIDE;
+
+    QList<QByteArray> devices(const QByteArray &service) const;
+    QString deviceDescription(const QByteArray &service, const QByteArray &device);
 };
 
 QT_END_NAMESPACE
diff --git a/src/plugins/android/src/src.pro b/src/plugins/android/src/src.pro
new file mode 100644
index 0000000000000000000000000000000000000000..e99fd30f55c59c85eb7dafa8c1ab49542ae051cd
--- /dev/null
+++ b/src/plugins/android/src/src.pro
@@ -0,0 +1,19 @@
+TARGET = qtmedia_android
+QT += multimedia-private gui-private platformsupport-private network
+
+PLUGIN_TYPE = mediaservice
+PLUGIN_CLASS_NAME = QAndroidMediaServicePlugin
+load(qt_plugin)
+
+HEADERS += \
+    qandroidmediaserviceplugin.h
+
+SOURCES += \
+    qandroidmediaserviceplugin.cpp
+
+include (wrappers/wrappers.pri)
+include (common/common.pri)
+include (mediaplayer/mediaplayer.pri)
+include (mediacapture/mediacapture.pri)
+
+OTHER_FILES += android_mediaservice.json
diff --git a/src/plugins/android/src/wrappers/jcamera.cpp b/src/plugins/android/src/wrappers/jcamera.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9005ac6e02313b4f5786ac8e47acb0f9a587f276
--- /dev/null
+++ b/src/plugins/android/src/wrappers/jcamera.cpp
@@ -0,0 +1,712 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jcamera.h"
+
+#include <QtPlatformSupport/private/qjnihelpers_p.h>
+#include <qstringlist.h>
+#include <qdebug.h>
+#include "qandroidmultimediautils.h"
+
+QT_BEGIN_NAMESPACE
+
+static jclass g_qtCameraClass = 0;
+static QMap<int, JCamera*> g_objectMap;
+
+static QRect areaToRect(jobject areaObj)
+{
+    QJNIObject area(areaObj);
+    QJNILocalRef<jobject> rectRef = area.getObjectField<jobject>("rect", "android/graphics/Rect");
+    QJNIObject rect(rectRef.object());
+
+    return QRect(rect.getField<jint>("left"),
+                 rect.getField<jint>("top"),
+                 rect.callMethod<jint>("width"),
+                 rect.callMethod<jint>("height"));
+}
+
+static QJNILocalRef<jobject> rectToArea(const QRect &rect)
+{
+    QJNIObject jrect("android/graphics/Rect",
+                     "(IIII)V",
+                     rect.left(), rect.top(), rect.right(), rect.bottom());
+
+    QJNIObject area("android/hardware/Camera$Area",
+                    "(Landroid/graphics/Rect;I)V",
+                    jrect.object(), 500);
+
+    return QJNILocalRef<jobject>(QAttachedJNIEnv()->NewLocalRef(area.object()));
+}
+
+// native method for QtCamera.java
+static void notifyAutoFocusComplete(JNIEnv* , jobject, int id, jboolean success)
+{
+    JCamera *obj = g_objectMap.value(id, 0);
+    if (obj)
+        Q_EMIT obj->autoFocusComplete(success);
+}
+
+static void notifyPictureExposed(JNIEnv* , jobject, int id)
+{
+    JCamera *obj = g_objectMap.value(id, 0);
+    if (obj)
+        Q_EMIT obj->pictureExposed();
+}
+
+static void notifyPictureCaptured(JNIEnv *env, jobject, int id, jbyteArray data)
+{
+    JCamera *obj = g_objectMap.value(id, 0);
+    if (obj) {
+        QByteArray bytes;
+        int arrayLength = env->GetArrayLength(data);
+        bytes.resize(arrayLength);
+        env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
+        Q_EMIT obj->pictureCaptured(bytes);
+    }
+}
+
+JCamera::JCamera(int cameraId, jobject cam)
+    : QObject()
+    , QJNIObject(cam)
+    , m_cameraId(cameraId)
+    , m_info(0)
+    , m_parameters(0)
+    , m_hasAPI14(false)
+{
+    if (isValid()) {
+        g_objectMap.insert(cameraId, this);
+
+        m_info = new QJNIObject("android/hardware/Camera$CameraInfo");
+        callStaticMethod<void>("android/hardware/Camera",
+                               "getCameraInfo",
+                               "(ILandroid/hardware/Camera$CameraInfo;)V",
+                               cameraId, m_info->object());
+
+        QJNILocalRef<jobject> params = callObjectMethod<jobject>("getParameters",
+                                                                 "()Landroid/hardware/Camera$Parameters;");
+        m_parameters = new QJNIObject(params.object());
+
+        // Check if API 14 is available
+        QAttachedJNIEnv env;
+        jclass clazz = env->FindClass("android/hardware/Camera");
+        if (env->ExceptionCheck()) {
+            clazz = 0;
+            env->ExceptionClear();
+        }
+        if (clazz) {
+            // startFaceDetection() was added in API 14
+            jmethodID id = env->GetMethodID(clazz, "startFaceDetection", "()V");
+            if (env->ExceptionCheck()) {
+                id = 0;
+                env->ExceptionClear();
+            }
+            m_hasAPI14 = bool(id);
+        }
+    }
+}
+
+JCamera::~JCamera()
+{
+    if (isValid())
+        g_objectMap.remove(m_cameraId);
+    delete m_parameters;
+    delete m_info;
+}
+
+JCamera *JCamera::open(int cameraId)
+{
+    QAttachedJNIEnv env;
+
+    QJNILocalRef<jobject> camera = callStaticObjectMethod<jobject>(g_qtCameraClass,
+                                                                   "open",
+                                                                   "(I)Lorg/qtproject/qt5/android/multimedia/QtCamera;",
+                                                                   cameraId);
+
+    if (camera.isNull())
+        return 0;
+    else
+        return new JCamera(cameraId, camera.object());
+}
+
+void JCamera::lock()
+{
+    callMethod<void>("lock");
+}
+
+void JCamera::unlock()
+{
+    callMethod<void>("unlock");
+}
+
+void JCamera::reconnect()
+{
+    callMethod<void>("reconnect");
+}
+
+void JCamera::release()
+{
+    m_previewSize = QSize();
+    delete m_parameters;
+    m_parameters = 0;
+    callMethod<void>("release");
+}
+
+JCamera::CameraFacing JCamera::getFacing()
+{
+    return CameraFacing(m_info->getField<jint>("facing"));
+}
+
+int JCamera::getNativeOrientation()
+{
+    return m_info->getField<jint>("orientation");
+}
+
+QSize JCamera::getPreferredPreviewSizeForVideo()
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return QSize();
+
+    QJNILocalRef<jobject> sizeRef = m_parameters->callObjectMethod<jobject>("getPreferredPreviewSizeForVideo",
+                                                                            "()Landroid/hardware/Camera$Size;");
+
+    QJNIObject size(sizeRef.object());
+    return QSize(size.getField<jint>("width"), size.getField<jint>("height"));
+}
+
+QList<QSize> JCamera::getSupportedPreviewSizes()
+{
+    QList<QSize> list;
+
+    if (m_parameters && m_parameters->isValid()) {
+        QJNILocalRef<jobject> sizeListRef = m_parameters->callObjectMethod<jobject>("getSupportedPreviewSizes",
+                                                                                    "()Ljava/util/List;");
+        QJNIObject sizeList(sizeListRef.object());
+        int count = sizeList.callMethod<jint>("size");
+        for (int i = 0; i < count; ++i) {
+            QJNILocalRef<jobject> sizeRef = sizeList.callObjectMethod<jobject>("get",
+                                                                               "(I)Ljava/lang/Object;",
+                                                                               i);
+            QJNIObject size(sizeRef.object());
+            list.append(QSize(size.getField<jint>("width"), size.getField<jint>("height")));
+        }
+
+        qSort(list.begin(), list.end(), qt_sizeLessThan);
+    }
+
+    return list;
+}
+
+void JCamera::setPreviewSize(const QSize &size)
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return;
+
+    m_previewSize = size;
+
+    m_parameters->callMethod<void>("setPreviewSize", "(II)V", size.width(), size.height());
+    applyParameters();
+
+    emit previewSizeChanged();
+}
+
+void JCamera::setPreviewTexture(jobject surfaceTexture)
+{
+    callMethod<void>("setPreviewTexture", "(Landroid/graphics/SurfaceTexture;)V", surfaceTexture);
+}
+
+bool JCamera::isZoomSupported()
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return false;
+
+    return m_parameters->callMethod<jboolean>("isZoomSupported");
+}
+
+int JCamera::getMaxZoom()
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return 0;
+
+    return m_parameters->callMethod<jint>("getMaxZoom");
+}
+
+QList<int> JCamera::getZoomRatios()
+{
+    QList<int> ratios;
+
+    if (m_parameters && m_parameters->isValid()) {
+        QJNILocalRef<jobject> ratioListRef = m_parameters->callObjectMethod<jobject>("getZoomRatios",
+                                                                                     "()Ljava/util/List;");
+        QJNIObject ratioList(ratioListRef.object());
+        int count = ratioList.callMethod<jint>("size");
+        for (int i = 0; i < count; ++i) {
+            QJNILocalRef<jobject> zoomRatioRef = ratioList.callObjectMethod<jobject>("get",
+                                                                                     "(I)Ljava/lang/Object;",
+                                                                                     i);
+
+            QJNIObject zoomRatio(zoomRatioRef.object());
+            ratios.append(zoomRatio.callMethod<jint>("intValue"));
+        }
+    }
+
+    return ratios;
+}
+
+int JCamera::getZoom()
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return 0;
+
+    return m_parameters->callMethod<jint>("getZoom");
+}
+
+void JCamera::setZoom(int value)
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return;
+
+    m_parameters->callMethod<void>("setZoom", "(I)V", value);
+    applyParameters();
+}
+
+QStringList JCamera::getSupportedFlashModes()
+{
+    return callStringListMethod("getSupportedFlashModes");
+}
+
+QString JCamera::getFlashMode()
+{
+    QString value;
+
+    if (m_parameters && m_parameters->isValid()) {
+        QJNILocalRef<jstring> flashMode = m_parameters->callObjectMethod<jstring>("getFlashMode",
+                                                                                  "()Ljava/lang/String;");
+        if (!flashMode.isNull())
+            value = qt_convertJString(flashMode.object());
+    }
+
+    return value;
+}
+
+void JCamera::setFlashMode(const QString &value)
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return;
+
+    m_parameters->callMethod<void>("setFlashMode",
+                                   "(Ljava/lang/String;)V",
+                                   qt_toJString(value).object());
+    applyParameters();
+}
+
+QStringList JCamera::getSupportedFocusModes()
+{
+    return callStringListMethod("getSupportedFocusModes");
+}
+
+QString JCamera::getFocusMode()
+{
+    QString value;
+
+    if (m_parameters && m_parameters->isValid()) {
+        QJNILocalRef<jstring> focusMode = m_parameters->callObjectMethod<jstring>("getFocusMode",
+                                                                                  "()Ljava/lang/String;");
+        if (!focusMode.isNull())
+            value = qt_convertJString(focusMode.object());
+    }
+
+    return value;
+}
+
+void JCamera::setFocusMode(const QString &value)
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return;
+
+    m_parameters->callMethod<void>("setFocusMode",
+                                   "(Ljava/lang/String;)V",
+                                   qt_toJString(value).object());
+    applyParameters();
+}
+
+int JCamera::getMaxNumFocusAreas()
+{
+    if (!m_hasAPI14 || !m_parameters || !m_parameters->isValid())
+        return 0;
+
+    return m_parameters->callMethod<jint>("getMaxNumFocusAreas");
+}
+
+QList<QRect> JCamera::getFocusAreas()
+{
+    QList<QRect> areas;
+
+    if (m_hasAPI14 && m_parameters && m_parameters->isValid()) {
+        QJNILocalRef<jobject> listRef = m_parameters->callObjectMethod<jobject>("getFocusAreas",
+                                                                                "()Ljava/util/List;");
+
+        if (!listRef.isNull()) {
+            QJNIObject list(listRef.object());
+            int count = list.callMethod<jint>("size");
+            for (int i = 0; i < count; ++i) {
+                QJNILocalRef<jobject> areaRef = list.callObjectMethod<jobject>("get",
+                                                                               "(I)Ljava/lang/Object;",
+                                                                               i);
+
+                areas.append(areaToRect(areaRef.object()));
+            }
+        }
+    }
+
+    return areas;
+}
+
+void JCamera::setFocusAreas(const QList<QRect> &areas)
+{
+    if (!m_hasAPI14 || !m_parameters || !m_parameters->isValid())
+        return;
+
+    QJNILocalRef<jobject> list(0);
+
+    if (!areas.isEmpty()) {
+        QAttachedJNIEnv env;
+        QJNIObject arrayList("java/util/ArrayList", "(I)V", areas.size());
+        for (int i = 0; i < areas.size(); ++i) {
+            arrayList.callMethod<jboolean>("add",
+                                           "(Ljava/lang/Object;)Z",
+                                           rectToArea(areas.at(i)).object());
+            if (env->ExceptionCheck())
+                env->ExceptionClear();
+        }
+        list = env->NewLocalRef(arrayList.object());
+    }
+
+    m_parameters->callMethod<void>("setFocusAreas", "(Ljava/util/List;)V", list.object());
+
+    applyParameters();
+}
+
+void JCamera::autoFocus()
+{
+    callMethod<void>("autoFocus");
+    emit autoFocusStarted();
+}
+
+void JCamera::cancelAutoFocus()
+{
+    callMethod<void>("cancelAutoFocus");
+}
+
+bool JCamera::isAutoExposureLockSupported()
+{
+    if (!m_hasAPI14 || !m_parameters || !m_parameters->isValid())
+        return false;
+
+    return m_parameters->callMethod<jboolean>("isAutoExposureLockSupported");
+}
+
+bool JCamera::getAutoExposureLock()
+{
+    if (!m_hasAPI14 || !m_parameters || !m_parameters->isValid())
+        return false;
+
+    return m_parameters->callMethod<jboolean>("getAutoExposureLock");
+}
+
+void JCamera::setAutoExposureLock(bool toggle)
+{
+    if (!m_hasAPI14 || !m_parameters || !m_parameters->isValid())
+        return;
+
+    m_parameters->callMethod<void>("setAutoExposureLock", "(Z)V", toggle);
+    applyParameters();
+}
+
+bool JCamera::isAutoWhiteBalanceLockSupported()
+{
+    if (!m_hasAPI14 || !m_parameters || !m_parameters->isValid())
+        return false;
+
+    return m_parameters->callMethod<jboolean>("isAutoWhiteBalanceLockSupported");
+}
+
+bool JCamera::getAutoWhiteBalanceLock()
+{
+    if (!m_hasAPI14 || !m_parameters || !m_parameters->isValid())
+        return false;
+
+    return m_parameters->callMethod<jboolean>("getAutoWhiteBalanceLock");
+}
+
+void JCamera::setAutoWhiteBalanceLock(bool toggle)
+{
+    if (!m_hasAPI14 || !m_parameters || !m_parameters->isValid())
+        return;
+
+    m_parameters->callMethod<void>("setAutoWhiteBalanceLock", "(Z)V", toggle);
+    applyParameters();
+}
+
+int JCamera::getExposureCompensation()
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return 0;
+
+    return m_parameters->callMethod<jint>("getExposureCompensation");
+}
+
+void JCamera::setExposureCompensation(int value)
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return;
+
+    m_parameters->callMethod<void>("setExposureCompensation", "(I)V", value);
+    applyParameters();
+}
+
+float JCamera::getExposureCompensationStep()
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return 0;
+
+    return m_parameters->callMethod<jfloat>("getExposureCompensationStep");
+}
+
+int JCamera::getMinExposureCompensation()
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return 0;
+
+    return m_parameters->callMethod<jint>("getMinExposureCompensation");
+}
+
+int JCamera::getMaxExposureCompensation()
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return 0;
+
+    return m_parameters->callMethod<jint>("getMaxExposureCompensation");
+}
+
+QStringList JCamera::getSupportedSceneModes()
+{
+    return callStringListMethod("getSupportedSceneModes");
+}
+
+QString JCamera::getSceneMode()
+{
+    QString value;
+
+    if (m_parameters && m_parameters->isValid()) {
+        QJNILocalRef<jstring> sceneMode = m_parameters->callObjectMethod<jstring>("getSceneMode",
+                                                                                  "()Ljava/lang/String;");
+        if (!sceneMode.isNull())
+            value = qt_convertJString(sceneMode.object());
+    }
+
+    return value;
+}
+
+void JCamera::setSceneMode(const QString &value)
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return;
+
+    m_parameters->callMethod<void>("setSceneMode",
+                                   "(Ljava/lang/String;)V",
+                                   qt_toJString(value).object());
+    applyParameters();
+}
+
+QStringList JCamera::getSupportedWhiteBalance()
+{
+    return callStringListMethod("getSupportedWhiteBalance");
+}
+
+QString JCamera::getWhiteBalance()
+{
+    QString value;
+
+    if (m_parameters && m_parameters->isValid()) {
+        QJNILocalRef<jstring> wb = m_parameters->callObjectMethod<jstring>("getWhiteBalance",
+                                                                           "()Ljava/lang/String;");
+        if (!wb.isNull())
+            value = qt_convertJString(wb.object());
+    }
+
+    return value;
+}
+
+void JCamera::setWhiteBalance(const QString &value)
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return;
+
+    m_parameters->callMethod<void>("setWhiteBalance",
+                                   "(Ljava/lang/String;)V",
+                                   qt_toJString(value).object());
+    applyParameters();
+
+    emit whiteBalanceChanged();
+}
+
+void JCamera::setRotation(int rotation)
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return;
+
+    m_parameters->callMethod<void>("setRotation", "(I)V", rotation);
+    applyParameters();
+}
+
+QList<QSize> JCamera::getSupportedPictureSizes()
+{
+    QList<QSize> list;
+
+    if (m_parameters && m_parameters->isValid()) {
+        QJNILocalRef<jobject> sizeListRef = m_parameters->callObjectMethod<jobject>("getSupportedPictureSizes",
+                                                                                    "()Ljava/util/List;");
+        QJNIObject sizeList(sizeListRef.object());
+        int count = sizeList.callMethod<jint>("size");
+        for (int i = 0; i < count; ++i) {
+            QJNILocalRef<jobject> sizeRef = sizeList.callObjectMethod<jobject>("get",
+                                                                               "(I)Ljava/lang/Object;",
+                                                                               i);
+            QJNIObject size(sizeRef.object());
+            list.append(QSize(size.getField<jint>("width"), size.getField<jint>("height")));
+        }
+
+        qSort(list.begin(), list.end(), qt_sizeLessThan);
+    }
+
+    return list;
+}
+
+void JCamera::setPictureSize(const QSize &size)
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return;
+
+    m_parameters->callMethod<void>("setPictureSize", "(II)V", size.width(), size.height());
+    applyParameters();
+}
+
+void JCamera::setJpegQuality(int quality)
+{
+    if (!m_parameters || !m_parameters->isValid())
+        return;
+
+    m_parameters->callMethod<void>("setJpegQuality", "(I)V", quality);
+    applyParameters();
+}
+
+void JCamera::takePicture()
+{
+    callMethod<void>("takePicture");
+}
+
+void JCamera::startPreview()
+{
+    callMethod<void>("startPreview");
+}
+
+void JCamera::stopPreview()
+{
+    callMethod<void>("stopPreview");
+}
+
+void JCamera::applyParameters()
+{
+    callMethod<void>("setParameters",
+                     "(Landroid/hardware/Camera$Parameters;)V",
+                     m_parameters->object());
+}
+
+QStringList JCamera::callStringListMethod(const char *methodName)
+{
+    QStringList stringList;
+
+    if (m_parameters && m_parameters->isValid()) {
+        QJNILocalRef<jobject> listRef = m_parameters->callObjectMethod<jobject>(methodName,
+                                                                                "()Ljava/util/List;");
+
+        if (!listRef.isNull()) {
+            QJNIObject list(listRef.object());
+            int count = list.callMethod<jint>("size");
+            for (int i = 0; i < count; ++i) {
+                QJNILocalRef<jobject> stringRef = list.callObjectMethod<jobject>("get",
+                                                                                 "(I)Ljava/lang/Object;",
+                                                                                 i);
+
+                QJNIObject string(stringRef.object());
+                stringList.append(qt_convertJString(string.callObjectMethod<jstring>("toString").object()));
+            }
+        }
+    }
+
+    return stringList;
+}
+
+static JNINativeMethod methods[] = {
+    {"notifyAutoFocusComplete", "(IZ)V", (void *)notifyAutoFocusComplete},
+    {"notifyPictureExposed", "(I)V", (void *)notifyPictureExposed},
+    {"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured}
+};
+
+bool JCamera::initJNI(JNIEnv *env)
+{
+    jclass clazz = env->FindClass("org/qtproject/qt5/android/multimedia/QtCamera");
+    if (env->ExceptionCheck())
+        env->ExceptionClear();
+
+    if (clazz) {
+        g_qtCameraClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+        if (env->RegisterNatives(g_qtCameraClass,
+                                 methods,
+                                 sizeof(methods) / sizeof(methods[0])) < 0) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/wrappers/jcamera.h b/src/plugins/android/src/wrappers/jcamera.h
new file mode 100644
index 0000000000000000000000000000000000000000..10062872196a3f3f5f3a438801290c9b96b6d2d3
--- /dev/null
+++ b/src/plugins/android/src/wrappers/jcamera.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JCAMERA_H
+#define JCAMERA_H
+
+#include <qobject.h>
+#include <QtPlatformSupport/private/qjniobject_p.h>
+#include <qsize.h>
+#include <qrect.h>
+
+QT_BEGIN_NAMESPACE
+
+class JCamera : public QObject, public QJNIObject
+{
+    Q_OBJECT
+public:
+    enum CameraFacing {
+        CameraFacingBack = 0,
+        CameraFacingFront = 1
+    };
+
+    ~JCamera();
+
+    static JCamera *open(int cameraId);
+
+    int cameraId() const { return m_cameraId; }
+
+    void lock();
+    void unlock();
+    void reconnect();
+    void release();
+
+    CameraFacing getFacing();
+    int getNativeOrientation();
+
+    QSize getPreferredPreviewSizeForVideo();
+    QList<QSize> getSupportedPreviewSizes();
+
+    QSize previewSize() const { return m_previewSize; }
+    void setPreviewSize(const QSize &size);
+    void setPreviewTexture(jobject surfaceTexture);
+
+    bool isZoomSupported();
+    int getMaxZoom();
+    QList<int> getZoomRatios();
+    int getZoom();
+    void setZoom(int value);
+
+    QStringList getSupportedFlashModes();
+    QString getFlashMode();
+    void setFlashMode(const QString &value);
+
+    QStringList getSupportedFocusModes();
+    QString getFocusMode();
+    void setFocusMode(const QString &value);
+
+    int getMaxNumFocusAreas();
+    QList<QRect> getFocusAreas();
+    void setFocusAreas(const QList<QRect> &areas);
+
+    void autoFocus();
+    void cancelAutoFocus();
+
+    bool isAutoExposureLockSupported();
+    bool getAutoExposureLock();
+    void setAutoExposureLock(bool toggle);
+
+    bool isAutoWhiteBalanceLockSupported();
+    bool getAutoWhiteBalanceLock();
+    void setAutoWhiteBalanceLock(bool toggle);
+
+    int getExposureCompensation();
+    void setExposureCompensation(int value);
+    float getExposureCompensationStep();
+    int getMinExposureCompensation();
+    int getMaxExposureCompensation();
+
+    QStringList getSupportedSceneModes();
+    QString getSceneMode();
+    void setSceneMode(const QString &value);
+
+    QStringList getSupportedWhiteBalance();
+    QString getWhiteBalance();
+    void setWhiteBalance(const QString &value);
+
+    void setRotation(int rotation);
+
+    QList<QSize> getSupportedPictureSizes();
+    void setPictureSize(const QSize &size);
+    void setJpegQuality(int quality);
+
+    void startPreview();
+    void stopPreview();
+
+    void takePicture();
+
+    static bool initJNI(JNIEnv *env);
+
+Q_SIGNALS:
+    void previewSizeChanged();
+
+    void autoFocusStarted();
+    void autoFocusComplete(bool success);
+
+    void whiteBalanceChanged();
+
+    void pictureExposed();
+    void pictureCaptured(const QByteArray &data);
+
+private:
+    JCamera(int cameraId, jobject cam);
+    void applyParameters();
+
+    QStringList callStringListMethod(const char *methodName);
+
+    int m_cameraId;
+    QJNIObject *m_info;
+    QJNIObject *m_parameters;
+
+    QSize m_previewSize;
+
+    bool m_hasAPI14;
+};
+
+QT_END_NAMESPACE
+
+#endif // JCAMERA_H
diff --git a/src/plugins/android/wrappers/jmediametadataretriever.cpp b/src/plugins/android/src/wrappers/jmediametadataretriever.cpp
similarity index 100%
rename from src/plugins/android/wrappers/jmediametadataretriever.cpp
rename to src/plugins/android/src/wrappers/jmediametadataretriever.cpp
diff --git a/src/plugins/android/wrappers/jmediametadataretriever.h b/src/plugins/android/src/wrappers/jmediametadataretriever.h
similarity index 100%
rename from src/plugins/android/wrappers/jmediametadataretriever.h
rename to src/plugins/android/src/wrappers/jmediametadataretriever.h
diff --git a/src/plugins/android/wrappers/jmediaplayer.cpp b/src/plugins/android/src/wrappers/jmediaplayer.cpp
similarity index 100%
rename from src/plugins/android/wrappers/jmediaplayer.cpp
rename to src/plugins/android/src/wrappers/jmediaplayer.cpp
diff --git a/src/plugins/android/wrappers/jmediaplayer.h b/src/plugins/android/src/wrappers/jmediaplayer.h
similarity index 100%
rename from src/plugins/android/wrappers/jmediaplayer.h
rename to src/plugins/android/src/wrappers/jmediaplayer.h
diff --git a/src/plugins/android/src/wrappers/jmediarecorder.cpp b/src/plugins/android/src/wrappers/jmediarecorder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b7cbe572456980b4dbbe70bcabb8ff8579c5e8b3
--- /dev/null
+++ b/src/plugins/android/src/wrappers/jmediarecorder.cpp
@@ -0,0 +1,242 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jmediarecorder.h"
+
+#include "jcamera.h"
+#include <QtPlatformSupport/private/qjnihelpers_p.h>
+#include <qmap.h>
+
+QT_BEGIN_NAMESPACE
+
+static jclass g_qtMediaRecorderClass = 0;
+static QMap<jlong, JMediaRecorder*> g_objectMap;
+
+static void notifyError(JNIEnv* , jobject, jlong id, jint what, jint extra)
+{
+    JMediaRecorder *obj = g_objectMap.value(id, 0);
+    if (obj)
+        emit obj->error(what, extra);
+}
+
+static void notifyInfo(JNIEnv* , jobject, jlong id, jint what, jint extra)
+{
+    JMediaRecorder *obj = g_objectMap.value(id, 0);
+    if (obj)
+        emit obj->info(what, extra);
+}
+
+JMediaRecorder::JMediaRecorder()
+    : QObject()
+    , QJNIObject(g_qtMediaRecorderClass, "(J)V", reinterpret_cast<jlong>(this))
+    , m_id(reinterpret_cast<jlong>(this))
+{
+    if (isValid())
+        g_objectMap.insert(m_id, this);
+}
+
+JMediaRecorder::~JMediaRecorder()
+{
+    g_objectMap.remove(m_id);
+}
+
+void JMediaRecorder::release()
+{
+    callMethod<void>("release");
+}
+
+bool JMediaRecorder::prepare()
+{
+    QAttachedJNIEnv env;
+    callMethod<void>("prepare");
+    if (env->ExceptionCheck()) {
+        env->ExceptionClear();
+        return false;
+    }
+    return true;
+}
+
+void JMediaRecorder::reset()
+{
+    callMethod<void>("reset");
+}
+
+bool JMediaRecorder::start()
+{
+    QAttachedJNIEnv env;
+    callMethod<void>("start");
+    if (env->ExceptionCheck()) {
+        env->ExceptionClear();
+        return false;
+    }
+    return true;
+}
+
+void JMediaRecorder::stop()
+{
+    QAttachedJNIEnv env;
+    callMethod<void>("stop");
+    if (env->ExceptionCheck())
+        env->ExceptionClear();
+}
+
+void JMediaRecorder::setAudioChannels(int numChannels)
+{
+    callMethod<void>("setAudioChannels", "(I)V", numChannels);
+}
+
+void JMediaRecorder::setAudioEncoder(AudioEncoder encoder)
+{
+    QAttachedJNIEnv env;
+    callMethod<void>("setAudioEncoder", "(I)V", int(encoder));
+    if (env->ExceptionCheck())
+        env->ExceptionClear();
+}
+
+void JMediaRecorder::setAudioEncodingBitRate(int bitRate)
+{
+    callMethod<void>("setAudioEncodingBitRate", "(I)V", bitRate);
+}
+
+void JMediaRecorder::setAudioSamplingRate(int samplingRate)
+{
+    callMethod<void>("setAudioSamplingRate", "(I)V", samplingRate);
+}
+
+void JMediaRecorder::setAudioSource(AudioSource source)
+{
+    QAttachedJNIEnv env;
+    callMethod<void>("setAudioSource", "(I)V", int(source));
+    if (env->ExceptionCheck())
+        env->ExceptionClear();
+}
+
+void JMediaRecorder::setCamera(JCamera *camera)
+{
+    QJNILocalRef<jobject> cam = camera->getObjectField<jobject>("m_camera", "Landroid/hardware/Camera;");
+    callMethod<void>("setCamera", "(Landroid/hardware/Camera;)V", cam.object());
+}
+
+void JMediaRecorder::setVideoEncoder(VideoEncoder encoder)
+{
+    QAttachedJNIEnv env;
+    callMethod<void>("setVideoEncoder", "(I)V", int(encoder));
+    if (env->ExceptionCheck())
+        env->ExceptionClear();
+}
+
+void JMediaRecorder::setVideoEncodingBitRate(int bitRate)
+{
+    callMethod<void>("setVideoEncodingBitRate", "(I)V", bitRate);
+}
+
+void JMediaRecorder::setVideoFrameRate(int rate)
+{
+    QAttachedJNIEnv env;
+    callMethod<void>("setVideoFrameRate", "(I)V", rate);
+    if (env->ExceptionCheck())
+        env->ExceptionClear();
+}
+
+void JMediaRecorder::setVideoSize(const QSize &size)
+{
+    QAttachedJNIEnv env;
+    callMethod<void>("setVideoSize", "(II)V", size.width(), size.height());
+    if (env->ExceptionCheck())
+        env->ExceptionClear();
+}
+
+void JMediaRecorder::setVideoSource(VideoSource source)
+{
+    QAttachedJNIEnv env;
+    callMethod<void>("setVideoSource", "(I)V", int(source));
+    if (env->ExceptionCheck())
+        env->ExceptionClear();
+}
+
+void JMediaRecorder::setOrientationHint(int degrees)
+{
+    QAttachedJNIEnv env;
+    callMethod<void>("setOrientationHint", "(I)V", degrees);
+    if (env->ExceptionCheck())
+        env->ExceptionClear();
+}
+
+void JMediaRecorder::setOutputFormat(OutputFormat format)
+{
+    QAttachedJNIEnv env;
+    callMethod<void>("setOutputFormat", "(I)V", int(format));
+    if (env->ExceptionCheck())
+        env->ExceptionClear();
+}
+
+void JMediaRecorder::setOutputFile(const QString &path)
+{
+    QAttachedJNIEnv env;
+    callMethod<void>("setOutputFile", "(Ljava/lang/String;)V", qt_toJString(path).object());
+    if (env->ExceptionCheck())
+        env->ExceptionClear();
+}
+
+static JNINativeMethod methods[] = {
+    {"notifyError", "(JII)V", (void *)notifyError},
+    {"notifyInfo", "(JII)V", (void *)notifyInfo}
+};
+
+bool JMediaRecorder::initJNI(JNIEnv *env)
+{
+    jclass clazz = env->FindClass("org/qtproject/qt5/android/multimedia/QtMediaRecorder");
+    if (env->ExceptionCheck())
+        env->ExceptionClear();
+
+    if (clazz) {
+        g_qtMediaRecorderClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+        if (env->RegisterNatives(g_qtMediaRecorderClass,
+                                 methods,
+                                 sizeof(methods) / sizeof(methods[0])) < 0) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/wrappers/jmediarecorder.h b/src/plugins/android/src/wrappers/jmediarecorder.h
new file mode 100644
index 0000000000000000000000000000000000000000..ef26b8a72a6b8f367bbaad25ac8c970d2e6a036d
--- /dev/null
+++ b/src/plugins/android/src/wrappers/jmediarecorder.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JMEDIARECORDER_H
+#define JMEDIARECORDER_H
+
+#include <qobject.h>
+#include <QtPlatformSupport/private/qjniobject_p.h>
+#include <qsize.h>
+
+QT_BEGIN_NAMESPACE
+
+class JCamera;
+
+class JMediaRecorder : public QObject, public QJNIObject
+{
+    Q_OBJECT
+public:
+    enum AudioEncoder {
+        DefaultAudioEncoder = 0,
+        AMR_NB_Encoder = 1,
+        AMR_WB_Encoder = 2,
+        AAC = 3
+    };
+
+    enum AudioSource {
+        DefaultAudioSource = 0,
+        Mic = 1,
+        VoiceUplink = 2,
+        VoiceDownlink = 3,
+        VoiceCall = 4,
+        Camcorder = 5,
+        VoiceRecognition = 6
+    };
+
+    enum VideoEncoder {
+        DefaultVideoEncoder = 0,
+        H263 = 1,
+        H264 = 2,
+        MPEG_4_SP = 3
+    };
+
+    enum VideoSource {
+        DefaultVideoSource = 0,
+        Camera = 1
+    };
+
+    enum OutputFormat {
+        DefaultOutputFormat = 0,
+        THREE_GPP = 1,
+        MPEG_4 = 2,
+        AMR_NB_Format = 3,
+        AMR_WB_Format = 4
+    };
+
+    JMediaRecorder();
+    ~JMediaRecorder();
+
+    void release();
+    bool prepare();
+    void reset();
+
+    bool start();
+    void stop();
+
+    void setAudioChannels(int numChannels);
+    void setAudioEncoder(AudioEncoder encoder);
+    void setAudioEncodingBitRate(int bitRate);
+    void setAudioSamplingRate(int samplingRate);
+    void setAudioSource(AudioSource source);
+
+    void setCamera(JCamera *camera);
+    void setVideoEncoder(VideoEncoder encoder);
+    void setVideoEncodingBitRate(int bitRate);
+    void setVideoFrameRate(int rate);
+    void setVideoSize(const QSize &size);
+    void setVideoSource(VideoSource source);
+
+    void setOrientationHint(int degrees);
+
+    void setOutputFormat(OutputFormat format);
+    void setOutputFile(const QString &path);
+
+    static bool initJNI(JNIEnv *env);
+
+Q_SIGNALS:
+    void error(int what, int extra);
+    void info(int what, int extra);
+
+private:
+    jlong m_id;
+};
+
+QT_END_NAMESPACE
+
+#endif // JMEDIARECORDER_H
diff --git a/src/plugins/android/src/wrappers/jmultimediautils.cpp b/src/plugins/android/src/wrappers/jmultimediautils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6832e6b6ed1ab19880428ce2cbbdfacfe93ff570
--- /dev/null
+++ b/src/plugins/android/src/wrappers/jmultimediautils.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jmultimediautils.h"
+
+#include <QtPlatformSupport/private/qjnihelpers_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static jclass g_qtMultimediaUtilsClass = 0;
+
+JMultimediaUtils::JMultimediaUtils()
+    : QObject()
+    , QJNIObject(g_qtMultimediaUtilsClass)
+{
+}
+
+void JMultimediaUtils::enableOrientationListener(bool enable)
+{
+    callStaticMethod<void>(g_qtMultimediaUtilsClass, "enableOrientationListener", "(Z)V", enable);
+}
+
+int JMultimediaUtils::getDeviceOrientation()
+{
+    return callStaticMethod<jint>(g_qtMultimediaUtilsClass, "getDeviceOrientation");
+}
+
+QString JMultimediaUtils::getDefaultMediaDirectory(MediaType type)
+{
+    QJNILocalRef<jstring> path = callStaticObjectMethod<jstring>(g_qtMultimediaUtilsClass,
+                                                                 "getDefaultMediaDirectory",
+                                                                 "(I)Ljava/lang/String;",
+                                                                 jint(type));
+    return qt_convertJString(path.object());
+}
+
+void JMultimediaUtils::registerMediaFile(const QString &file)
+{
+    callStaticMethod<void>(g_qtMultimediaUtilsClass,
+                           "registerMediaFile",
+                           "(Ljava/lang/String;)V",
+                           qt_toJString(file).object());
+}
+
+bool JMultimediaUtils::initJNI(JNIEnv *env)
+{
+    jclass clazz = env->FindClass("org/qtproject/qt5/android/multimedia/QtMultimediaUtils");
+    if (env->ExceptionCheck())
+        env->ExceptionClear();
+
+    if (clazz)
+        g_qtMultimediaUtilsClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+    return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/src/wrappers/jmultimediautils.h b/src/plugins/android/src/wrappers/jmultimediautils.h
new file mode 100644
index 0000000000000000000000000000000000000000..909f5c1554a190942460d8acc6e4c4601130e569
--- /dev/null
+++ b/src/plugins/android/src/wrappers/jmultimediautils.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JMULTIMEDIAUTILS_H
+#define JMULTIMEDIAUTILS_H
+
+#include <qobject.h>
+#include <QtPlatformSupport/private/qjniobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class JMultimediaUtils : public QObject, public QJNIObject
+{
+    Q_OBJECT
+public:
+    enum MediaType {
+        Music = 0,
+        Movies = 1,
+        DCIM = 2,
+        Sounds = 3
+    };
+
+    JMultimediaUtils();
+
+    static void enableOrientationListener(bool enable);
+    static int getDeviceOrientation();
+    static QString getDefaultMediaDirectory(MediaType type);
+    static void registerMediaFile(const QString &file);
+
+    static bool initJNI(JNIEnv *env);
+};
+
+QT_END_NAMESPACE
+
+#endif // JMULTIMEDIAUTILS_H
diff --git a/src/plugins/android/wrappers/jsurfacetexture.cpp b/src/plugins/android/src/wrappers/jsurfacetexture.cpp
similarity index 94%
rename from src/plugins/android/wrappers/jsurfacetexture.cpp
rename to src/plugins/android/src/wrappers/jsurfacetexture.cpp
index 34edf1b66cf4f91d4554147a1f41f66bbc4769c6..60c85cdf0ebd9abb9068adac9aa86bbeae5618e5 100644
--- a/src/plugins/android/wrappers/jsurfacetexture.cpp
+++ b/src/plugins/android/src/wrappers/jsurfacetexture.cpp
@@ -45,7 +45,7 @@
 QT_BEGIN_NAMESPACE
 
 static jclass g_qtSurfaceTextureClass = 0;
-static QHash<int, JSurfaceTexture*> g_objectMap;
+static QMap<int, JSurfaceTexture*> g_objectMap;
 
 // native method for QtSurfaceTexture.java
 static void notifyFrameAvailable(JNIEnv* , jobject, int id)
@@ -88,11 +88,6 @@ void JSurfaceTexture::updateTexImage()
     callMethod<void>("updateTexImage");
 }
 
-QJNILocalRef<jobject> JSurfaceTexture::surfaceTexture()
-{
-    return getObjectField<jobject>("surfaceTexture", "Landroid/graphics/SurfaceTexture;");
-}
-
 static JNINativeMethod methods[] = {
     {"notifyFrameAvailable", "(I)V", (void *)notifyFrameAvailable}
 };
diff --git a/src/plugins/android/wrappers/jsurfacetexture.h b/src/plugins/android/src/wrappers/jsurfacetexture.h
similarity index 98%
rename from src/plugins/android/wrappers/jsurfacetexture.h
rename to src/plugins/android/src/wrappers/jsurfacetexture.h
index 49e0076669034d03ff48fd337a6610580c8d1276..2a2f27ae37c998f7ef76e76a9c4badb5667bcc70 100644
--- a/src/plugins/android/wrappers/jsurfacetexture.h
+++ b/src/plugins/android/src/wrappers/jsurfacetexture.h
@@ -59,8 +59,6 @@ public:
     QMatrix4x4 getTransformMatrix();
     void updateTexImage();
 
-    QJNILocalRef<jobject> surfaceTexture();
-
     static bool initJNI(JNIEnv *env);
 
 Q_SIGNALS:
diff --git a/src/plugins/android/wrappers/jsurfacetextureholder.cpp b/src/plugins/android/src/wrappers/jsurfacetextureholder.cpp
similarity index 100%
rename from src/plugins/android/wrappers/jsurfacetextureholder.cpp
rename to src/plugins/android/src/wrappers/jsurfacetextureholder.cpp
diff --git a/src/plugins/android/wrappers/jsurfacetextureholder.h b/src/plugins/android/src/wrappers/jsurfacetextureholder.h
similarity index 100%
rename from src/plugins/android/wrappers/jsurfacetextureholder.h
rename to src/plugins/android/src/wrappers/jsurfacetextureholder.h
diff --git a/src/plugins/android/wrappers/wrappers.pri b/src/plugins/android/src/wrappers/wrappers.pri
similarity index 52%
rename from src/plugins/android/wrappers/wrappers.pri
rename to src/plugins/android/src/wrappers/wrappers.pri
index 5b47ef53136563faa7cfc0e29a6a415af7d50a65..b2faa5b79d8b3c17206c8ac0669b185397c89937 100644
--- a/src/plugins/android/wrappers/wrappers.pri
+++ b/src/plugins/android/src/wrappers/wrappers.pri
@@ -6,10 +6,16 @@ HEADERS += \
     $$PWD/jmediaplayer.h \
     $$PWD/jsurfacetexture.h \
     $$PWD/jsurfacetextureholder.h \
-    $$PWD/jmediametadataretriever.h
+    $$PWD/jmediametadataretriever.h \
+    $$PWD/jcamera.h \
+    $$PWD/jmultimediautils.h \
+    $$PWD/jmediarecorder.h
 
 SOURCES += \
     $$PWD/jmediaplayer.cpp \
     $$PWD/jsurfacetexture.cpp \
     $$PWD/jsurfacetextureholder.cpp \
-    $$PWD/jmediametadataretriever.cpp
+    $$PWD/jmediametadataretriever.cpp \
+    $$PWD/jcamera.cpp \
+    $$PWD/jmultimediautils.cpp \
+    $$PWD/jmediarecorder.cpp
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index b0356636aca33dd33e462b618e78834f33e7e951..742a4f7f0ca95c277cf443b21905626e340eb847 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -29,7 +29,7 @@ win32 {
     config_wmf: SUBDIRS += wmf
 }
 
-unix:!mac {
+unix:!mac:!android {
     config_gstreamer {
        SUBDIRS += gstreamer
     } else {