Merge "frameworks/av: Documentation fixes for AImage and AImageReader." into pi-dev
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 5fd4886..2829b90 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -4807,6 +4807,8 @@
      * of points can be less than max (that is, the request doesn't have to
      * always provide a curve with number of points equivalent to
      * ACAMERA_TONEMAP_MAX_CURVE_POINTS).</p>
+     * <p>For devices with MONOCHROME capability, only red channel is used. Green and blue channels
+     * are ignored.</p>
      * <p>A few examples, and their corresponding graphical mappings; these
      * only specify the red channel and the precision is limited to 4
      * digits, for conciseness.</p>
@@ -7094,6 +7096,12 @@
      */
     ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA      = 11,
 
+    /**
+     * <p>The camera device is a monochrome camera that doesn't contain a color filter array,
+     * and the pixel values on U and Y planes are all 128.</p>
+     */
+    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME                = 12,
+
 } acamera_metadata_enum_android_request_available_capabilities_t;
 
 
diff --git a/media/mtp/Android.bp b/media/mtp/Android.bp
index acea373..2cf9b82 100644
--- a/media/mtp/Android.bp
+++ b/media/mtp/Android.bp
@@ -49,7 +49,6 @@
     shared_libs: [
         "libasyncio",
         "libbase",
-        "libutils",
         "liblog",
         "libusbhost",
     ],
diff --git a/media/mtp/IMtpDatabase.h b/media/mtp/IMtpDatabase.h
index d09a984..1245092 100644
--- a/media/mtp/IMtpDatabase.h
+++ b/media/mtp/IMtpDatabase.h
@@ -24,6 +24,7 @@
 class MtpDataPacket;
 class MtpProperty;
 class MtpObjectInfo;
+class MtpStringBuffer;
 
 class IMtpDatabase {
 public:
@@ -86,7 +87,7 @@
     virtual void*                   getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) = 0;
 
     virtual MtpResponseCode         getObjectFilePath(MtpObjectHandle handle,
-                                            MtpString& outFilePath,
+                                            MtpStringBuffer& outFilePath,
                                             int64_t& outFileLength,
                                             MtpObjectFormat& outFormat) = 0;
 
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index d1c71d7..992dc9a 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -19,6 +19,7 @@
 #include "MtpDataPacket.h"
 
 #include <algorithm>
+#include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <sys/types.h>
@@ -129,7 +130,7 @@
             delete result;
             return NULL;
         }
-        result->push(value);
+        result->push_back(value);
     }
     return result;
 }
@@ -145,7 +146,7 @@
             delete result;
             return NULL;
         }
-        result->push(value);
+        result->push_back(value);
     }
     return result;
 }
@@ -161,7 +162,7 @@
             delete result;
             return NULL;
         }
-        result->push(value);
+        result->push_back(value);
     }
     return result;
 }
@@ -177,7 +178,7 @@
             delete result;
             return NULL;
         }
-        result->push(value);
+        result->push_back(value);
     }
     return result;
 }
@@ -193,7 +194,7 @@
             delete result;
             return NULL;
         }
-        result->push(value);
+        result->push_back(value);
     }
     return result;
 }
@@ -209,7 +210,7 @@
             delete result;
             return NULL;
         }
-        result->push(value);
+        result->push_back(value);
     }
     return result;
 }
@@ -225,7 +226,7 @@
             delete result;
             return NULL;
         }
-        result->push(value);
+        result->push_back(value);
     }
     return result;
 }
@@ -241,7 +242,7 @@
             delete result;
             return NULL;
         }
-        result->push(value);
+        result->push_back(value);
     }
     return result;
 }
diff --git a/media/mtp/MtpDebug.h b/media/mtp/MtpDebug.h
index 5b53e31..8d48273 100644
--- a/media/mtp/MtpDebug.h
+++ b/media/mtp/MtpDebug.h
@@ -18,10 +18,10 @@
 #define _MTP_DEBUG_H
 
 // #define LOG_NDEBUG 0
-#include <utils/Log.h>
-
 #include "MtpTypes.h"
 
+#include <log/log.h>
+
 namespace android {
 
 class MtpDebug {
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 0bf7854..993797a 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -262,7 +262,7 @@
                 MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
                 MtpProperty* property = getDevicePropDesc(propCode);
                 if (property)
-                    mDeviceProperties.push(property);
+                    mDeviceProperties.push_back(property);
             }
         }
     }
@@ -327,7 +327,7 @@
 }
 
 bool MtpDevice::openSession() {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     mSessionID = 0;
     mTransactionID = 0;
@@ -353,7 +353,7 @@
 }
 
 MtpDeviceInfo* MtpDevice::getDeviceInfo() {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     mRequest.reset();
     if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
@@ -372,7 +372,7 @@
 }
 
 MtpStorageIDList* MtpDevice::getStorageIDs() {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     mRequest.reset();
     if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
@@ -387,7 +387,7 @@
 }
 
 MtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     mRequest.reset();
     mRequest.setParameter(1, storageID);
@@ -408,7 +408,7 @@
 
 MtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
             MtpObjectFormat format, MtpObjectHandle parent) {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     mRequest.reset();
     mRequest.setParameter(1, storageID);
@@ -426,7 +426,7 @@
 }
 
 MtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     // FIXME - we might want to add some caching here
 
@@ -448,7 +448,7 @@
 }
 
 void* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     mRequest.reset();
     mRequest.setParameter(1, handle);
@@ -463,7 +463,7 @@
 }
 
 MtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     mRequest.reset();
     MtpObjectHandle parent = info->mParent;
@@ -517,7 +517,7 @@
 }
 
 bool MtpDevice::sendObject(MtpObjectHandle handle, int size, int srcFD) {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     if (mLastSendObjectInfoTransactionID + 1 != mTransactionID ||
             mLastSendObjectInfoObjectHandle != handle) {
@@ -537,7 +537,7 @@
 }
 
 bool MtpDevice::deleteObject(MtpObjectHandle handle) {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     mRequest.reset();
     mRequest.setParameter(1, handle);
@@ -572,7 +572,7 @@
 }
 
 MtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     mRequest.reset();
     mRequest.setParameter(1, format);
@@ -589,7 +589,7 @@
 }
 
 MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     mRequest.reset();
     mRequest.setParameter(1, code);
@@ -609,7 +609,7 @@
 }
 
 MtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     mRequest.reset();
     mRequest.setParameter(1, code);
@@ -633,7 +633,7 @@
     if (property == nullptr)
         return false;
 
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     mRequest.reset();
     mRequest.setParameter(1, handle);
@@ -684,7 +684,7 @@
                                    ReadObjectCallback callback,
                                    const uint32_t* expectedLength,
                                    void* clientData) {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     mRequest.reset();
     mRequest.setParameter(1, handle);
@@ -806,7 +806,7 @@
                                   uint32_t *writtenSize,
                                   ReadObjectCallback callback,
                                   void* clientData) {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     mRequest.reset();
     mRequest.setParameter(1, handle);
@@ -828,7 +828,7 @@
                                     uint32_t *writtenSize,
                                     ReadObjectCallback callback,
                                     void* clientData) {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     mRequest.reset();
     mRequest.setParameter(1, handle);
@@ -908,7 +908,7 @@
 }
 
 int MtpDevice::submitEventRequest() {
-    if (mEventMutex.tryLock()) {
+    if (!mEventMutex.try_lock()) {
         // An event is being reaped on another thread.
         return -1;
     }
@@ -916,7 +916,7 @@
         // An event request was submitted, but no reapEventRequest called so far.
         return -1;
     }
-    Mutex::Autolock autoLock(mEventMutexForInterrupt);
+    std::lock_guard<std::mutex> lg(mEventMutexForInterrupt);
     mEventPacket.sendRequest(mRequestIntr);
     const int currentHandle = ++mCurrentEventHandle;
     mProcessingEvent = true;
@@ -925,7 +925,7 @@
 }
 
 int MtpDevice::reapEventRequest(int handle, uint32_t (*parameters)[3]) {
-    Mutex::Autolock autoLock(mEventMutex);
+    std::lock_guard<std::mutex> lg(mEventMutex);
     if (!mProcessingEvent || mCurrentEventHandle != handle || !parameters) {
         return -1;
     }
@@ -940,7 +940,7 @@
 }
 
 void MtpDevice::discardEventRequest(int handle) {
-    Mutex::Autolock autoLock(mEventMutexForInterrupt);
+    std::lock_guard<std::mutex> lg(mEventMutexForInterrupt);
     if (mCurrentEventHandle != handle) {
         return;
     }
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
index a9a3e0e..8cf9e5e 100644
--- a/media/mtp/MtpDevice.h
+++ b/media/mtp/MtpDevice.h
@@ -23,7 +23,7 @@
 #include "MtpResponsePacket.h"
 #include "MtpTypes.h"
 
-#include <utils/threads.h>
+#include <mutex>
 
 struct usb_device;
 struct usb_request;
@@ -67,9 +67,9 @@
     MtpObjectHandle         mLastSendObjectInfoObjectHandle;
 
     // to ensure only one MTP transaction at a time
-    Mutex                   mMutex;
-    Mutex                   mEventMutex;
-    Mutex                   mEventMutexForInterrupt;
+    std::mutex              mMutex;
+    std::mutex              mEventMutex;
+    std::mutex              mEventMutexForInterrupt;
 
     // Remember the device's packet division mode.
     UrbPacketDivisionMode   mPacketDivisionMode;
diff --git a/media/mtp/MtpEventPacket.h b/media/mtp/MtpEventPacket.h
index 3f3b6a3..94d6ebf 100644
--- a/media/mtp/MtpEventPacket.h
+++ b/media/mtp/MtpEventPacket.h
@@ -20,6 +20,8 @@
 #include "MtpPacket.h"
 #include "mtp.h"
 
+#include <errno.h>
+
 class IMtpHandle;
 
 namespace android {
diff --git a/media/mtp/MtpPacket.h b/media/mtp/MtpPacket.h
index d47c91d..9842b28 100644
--- a/media/mtp/MtpPacket.h
+++ b/media/mtp/MtpPacket.h
@@ -19,6 +19,7 @@
 
 #include <android-base/macros.h>
 
+#include "MtpDebug.h"
 #include "MtpTypes.h"
 
 struct usb_device;
diff --git a/media/mtp/MtpProperty.cpp b/media/mtp/MtpProperty.cpp
index 039e4f5..5c02a0d 100644
--- a/media/mtp/MtpProperty.cpp
+++ b/media/mtp/MtpProperty.cpp
@@ -18,6 +18,10 @@
 
 #include <inttypes.h>
 #include <cutils/compiler.h>
+#include <iomanip>
+#include <sstream>
+#include <string>
+
 #include "MtpDataPacket.h"
 #include "MtpDebug.h"
 #include "MtpProperty.h"
@@ -336,7 +340,7 @@
 }
 
 void MtpProperty::print() {
-    MtpString buffer;
+    std::string buffer;
     bool deviceProp = isDeviceProperty();
     if (deviceProp)
         ALOGI("    %s (%04X)", MtpDebug::getDevicePropCodeName(mCode), mCode);
@@ -346,11 +350,11 @@
     ALOGI("    writeable %s", (mWriteable ? "true" : "false"));
     buffer = "    default value: ";
     print(mDefaultValue, buffer);
-    ALOGI("%s", (const char *)buffer);
+    ALOGI("%s", buffer.c_str());
     if (deviceProp) {
         buffer = "    current value: ";
         print(mCurrentValue, buffer);
-        ALOGI("%s", (const char *)buffer);
+        ALOGI("%s", buffer.c_str());
     }
     switch (mFormFlag) {
         case kFormNone:
@@ -363,7 +367,7 @@
             buffer += ", ";
             print(mStepSize, buffer);
             buffer += ")";
-            ALOGI("%s", (const char *)buffer);
+            ALOGI("%s", buffer.c_str());
             break;
         case kFormEnum:
             buffer = "    Enum { ";
@@ -372,7 +376,7 @@
                 buffer += " ";
             }
             buffer += "}";
-            ALOGI("%s", (const char *)buffer);
+            ALOGI("%s", buffer.c_str());
             break;
         case kFormDateTime:
             ALOGI("    DateTime\n");
@@ -383,42 +387,47 @@
     }
 }
 
-void MtpProperty::print(MtpPropertyValue& value, MtpString& buffer) {
+void MtpProperty::print(MtpPropertyValue& value, std::string& buffer) {
+    std::ostringstream s;
     switch (mType) {
         case MTP_TYPE_INT8:
-            buffer.appendFormat("%d", value.u.i8);
+            buffer += std::to_string(value.u.i8);
             break;
         case MTP_TYPE_UINT8:
-            buffer.appendFormat("%d", value.u.u8);
+            buffer += std::to_string(value.u.u8);
             break;
         case MTP_TYPE_INT16:
-            buffer.appendFormat("%d", value.u.i16);
+            buffer += std::to_string(value.u.i16);
             break;
         case MTP_TYPE_UINT16:
-            buffer.appendFormat("%d", value.u.u16);
+            buffer += std::to_string(value.u.u16);
             break;
         case MTP_TYPE_INT32:
-            buffer.appendFormat("%d", value.u.i32);
+            buffer += std::to_string(value.u.i32);
             break;
         case MTP_TYPE_UINT32:
-            buffer.appendFormat("%d", value.u.u32);
+            buffer += std::to_string(value.u.u32);
             break;
         case MTP_TYPE_INT64:
-            buffer.appendFormat("%" PRId64, value.u.i64);
+            buffer += std::to_string(value.u.i64);
             break;
         case MTP_TYPE_UINT64:
-            buffer.appendFormat("%" PRIu64, value.u.u64);
+            buffer += std::to_string(value.u.u64);
             break;
         case MTP_TYPE_INT128:
-            buffer.appendFormat("%08X%08X%08X%08X", value.u.i128[0], value.u.i128[1],
-                    value.u.i128[2], value.u.i128[3]);
+            for (auto i : value.u.i128) {
+                s << std::hex << std::setfill('0') << std::uppercase << i;
+            }
+            buffer += s.str();
             break;
         case MTP_TYPE_UINT128:
-            buffer.appendFormat("%08X%08X%08X%08X", value.u.u128[0], value.u.u128[1],
-                    value.u.u128[2], value.u.u128[3]);
+            for (auto i : value.u.u128) {
+                s << std::hex << std::setfill('0') << std::uppercase << i;
+            }
+            buffer += s.str();
             break;
         case MTP_TYPE_STR:
-            buffer.appendFormat("%s", value.str);
+            buffer += value.str;
             break;
         default:
             ALOGE("unsupported type for MtpProperty::print\n");
diff --git a/media/mtp/MtpProperty.h b/media/mtp/MtpProperty.h
index 03c08e1..bfd5f7f 100644
--- a/media/mtp/MtpProperty.h
+++ b/media/mtp/MtpProperty.h
@@ -19,6 +19,8 @@
 
 #include "MtpTypes.h"
 
+#include <string>
+
 namespace android {
 
 class MtpDataPacket;
@@ -97,7 +99,6 @@
     void                setFormDateTime();
 
     void                print();
-    void                print(MtpPropertyValue& value, MtpString& buffer);
 
     inline bool         isDeviceProperty() const {
                             return (   ((mCode & 0xF000) == 0x5000)
@@ -110,6 +111,7 @@
     MtpPropertyValue*   readArrayValues(MtpDataPacket& packet, uint32_t& length);
     void                writeArrayValues(MtpDataPacket& packet,
                                             MtpPropertyValue* values, uint32_t length);
+    void                print(MtpPropertyValue& value, std::string& buffer);
 };
 
 }; // namespace android
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index e4ac8b0..86d59dd 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -102,10 +102,10 @@
 };
 
 MtpServer::MtpServer(IMtpDatabase* database, int controlFd, bool ptp,
-                    const MtpString& deviceInfoManufacturer,
-                    const MtpString& deviceInfoModel,
-                    const MtpString& deviceInfoDeviceVersion,
-                    const MtpString& deviceInfoSerialNumber)
+                    const char *deviceInfoManufacturer,
+                    const char *deviceInfoModel,
+                    const char *deviceInfoDeviceVersion,
+                    const char *deviceInfoSerialNumber)
     :   mDatabase(database),
         mPtp(ptp),
         mDeviceInfoManufacturer(deviceInfoManufacturer),
@@ -132,14 +132,14 @@
 }
 
 void MtpServer::addStorage(MtpStorage* storage) {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
-    mStorages.push(storage);
+    mStorages.push_back(storage);
     sendStoreAdded(storage->getStorageID());
 }
 
 void MtpServer::removeStorage(MtpStorage* storage) {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
     auto iter = std::find(mStorages.begin(), mStorages.end(), storage);
     if (iter != mStorages.end()) {
         sendStoreRemoved(storage->getStorageID());
@@ -284,10 +284,10 @@
     }
 }
 
-void MtpServer::addEditObject(MtpObjectHandle handle, MtpString& path,
+void MtpServer::addEditObject(MtpObjectHandle handle, MtpStringBuffer& path,
         uint64_t size, MtpObjectFormat format, int fd) {
     ObjectEdit*  edit = new ObjectEdit(handle, path, size, format, fd);
-    mObjectEditList.add(edit);
+    mObjectEditList.push_back(edit);
 }
 
 MtpServer::ObjectEdit* MtpServer::getEditObject(MtpObjectHandle handle) {
@@ -305,7 +305,7 @@
         ObjectEdit* edit = mObjectEditList[i];
         if (edit->mHandle == handle) {
             delete edit;
-            mObjectEditList.removeAt(i);
+            mObjectEditList.erase(mObjectEditList.begin() + i);
             return;
         }
     }
@@ -318,7 +318,7 @@
 
 
 bool MtpServer::handleRequest() {
-    Mutex::Autolock autoLock(mMutex);
+    std::lock_guard<std::mutex> lg(mMutex);
 
     MtpOperationCode operation = mRequest.getOperationCode();
     MtpResponseCode response;
@@ -769,7 +769,7 @@
     if (mRequest.getParameterCount() < 1)
         return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectHandle handle = mRequest.getParameter(1);
-    MtpString pathBuf;
+    MtpStringBuffer pathBuf;
     int64_t fileLength;
     MtpObjectFormat format;
     int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
@@ -855,7 +855,7 @@
         // standard GetPartialObject
         length = mRequest.getParameter(3);
     }
-    MtpString pathBuf;
+    MtpStringBuffer pathBuf;
     int64_t fileLength;
     MtpObjectFormat format;
     int result = mDatabase->getObjectFilePath(handle, pathBuf, fileLength, format);
@@ -892,7 +892,7 @@
 }
 
 MtpResponseCode MtpServer::doSendObjectInfo() {
-    MtpString path;
+    MtpStringBuffer path;
     uint16_t temp16;
     uint32_t temp32;
 
@@ -906,7 +906,7 @@
 
     // special case the root
     if (parent == MTP_PARENT_ROOT) {
-        path = storage->getPath();
+        path.set(storage->getPath());
         parent = 0;
     } else {
         int64_t length;
@@ -938,7 +938,7 @@
     if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // sequence number
     MtpStringBuffer name, created, modified;
     if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER;    // file name
-    if (name.getCharCount() == 0) {
+    if (name.isEmpty()) {
         ALOGE("empty name");
         return MTP_RESPONSE_INVALID_PARAMETER;
     }
@@ -952,8 +952,8 @@
         modifiedTime = 0;
 
     if (path[path.size() - 1] != '/')
-        path += "/";
-    path += (const char *)name;
+        path.append("/");
+    path.append(name);
 
     // check space first
     if (mSendObjectFileSize > storage->getFreeSpace())
@@ -1006,10 +1006,10 @@
     MtpObjectHandle parent = mRequest.getParameter(3);
     if (!storage)
         return MTP_RESPONSE_INVALID_STORAGE_ID;
-    MtpString path;
+    MtpStringBuffer path;
     MtpResponseCode result;
 
-    MtpString fromPath;
+    MtpStringBuffer fromPath;
     int64_t fileLength;
     MtpObjectFormat format;
     MtpObjectInfo info(objectHandle);
@@ -1022,7 +1022,7 @@
 
     // special case the root
     if (parent == 0) {
-        path = storage->getPath();
+        path.set(storage->getPath());
     } else {
         int64_t parentLength;
         MtpObjectFormat parentFormat;
@@ -1034,8 +1034,8 @@
     }
 
     if (path[path.size() - 1] != '/')
-        path += "/";
-    path += info.mName;
+        path.append("/");
+    path.append(info.mName);
 
     result = mDatabase->beginMoveObject(objectHandle, parent, storageID);
     if (result != MTP_RESPONSE_OK)
@@ -1085,9 +1085,9 @@
     MtpObjectHandle parent = mRequest.getParameter(3);
     if (!storage)
         return MTP_RESPONSE_INVALID_STORAGE_ID;
-    MtpString path;
+    MtpStringBuffer path;
 
-    MtpString fromPath;
+    MtpStringBuffer fromPath;
     int64_t fileLength;
     MtpObjectFormat format;
     MtpObjectInfo info(objectHandle);
@@ -1100,7 +1100,7 @@
 
     // special case the root
     if (parent == 0) {
-        path = storage->getPath();
+        path.set(storage->getPath());
     } else {
         int64_t parentLength;
         MtpObjectFormat parentFormat;
@@ -1116,8 +1116,8 @@
         return MTP_RESPONSE_STORAGE_FULL;
 
     if (path[path.size() - 1] != '/')
-        path += "/";
-    path += info.mName;
+        path.append("/");
+    path.append(info.mName);
 
     MtpObjectHandle handle = mDatabase->beginCopyObject(objectHandle, parent, storageID);
     if (handle == kInvalidObjectHandle) {
@@ -1264,7 +1264,7 @@
     // FIXME - support deleting all objects if handle is 0xFFFFFFFF
     // FIXME - implement deleting objects by format
 
-    MtpString filePath;
+    MtpStringBuffer filePath;
     int64_t fileLength;
     int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
     if (result != MTP_RESPONSE_OK)
@@ -1414,7 +1414,7 @@
         return MTP_RESPONSE_GENERAL_ERROR;
     }
 
-    MtpString path;
+    MtpStringBuffer path;
     int64_t fileLength;
     MtpObjectFormat format;
     int result = mDatabase->getObjectFilePath(handle, path, fileLength, format);
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index e633c52..f6939d7 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -21,14 +21,14 @@
 #include "MtpDataPacket.h"
 #include "MtpResponsePacket.h"
 #include "MtpEventPacket.h"
+#include "MtpStringBuffer.h"
 #include "mtp.h"
 #include "MtpUtils.h"
 #include "IMtpHandle.h"
 
-#include <utils/threads.h>
-#include <queue>
 #include <memory>
 #include <mutex>
+#include <queue>
 
 namespace android {
 
@@ -44,13 +44,13 @@
     bool                mPtp;
 
     // Manufacturer to report in DeviceInfo
-    MtpString           mDeviceInfoManufacturer;
+    MtpStringBuffer     mDeviceInfoManufacturer;
     // Model to report in DeviceInfo
-    MtpString           mDeviceInfoModel;
+    MtpStringBuffer     mDeviceInfoModel;
     // Device version to report in DeviceInfo
-    MtpString           mDeviceInfoDeviceVersion;
+    MtpStringBuffer     mDeviceInfoDeviceVersion;
     // Serial number to report in DeviceInfo
-    MtpString           mDeviceInfoSerialNumber;
+    MtpStringBuffer     mDeviceInfoSerialNumber;
 
     // current session ID
     MtpSessionID        mSessionID;
@@ -70,18 +70,18 @@
     // handle for new object, set by SendObjectInfo and used by SendObject
     MtpObjectHandle     mSendObjectHandle;
     MtpObjectFormat     mSendObjectFormat;
-    MtpString           mSendObjectFilePath;
+    MtpStringBuffer     mSendObjectFilePath;
     size_t              mSendObjectFileSize;
     time_t              mSendObjectModifiedTime;
 
-    Mutex               mMutex;
+    std::mutex          mMutex;
 
     // represents an MTP object that is being edited using the android extensions
     // for direct editing (BeginEditObject, SendPartialObject, TruncateObject and EndEditObject)
     class ObjectEdit {
         public:
         MtpObjectHandle     mHandle;
-        MtpString           mPath;
+        MtpStringBuffer           mPath;
         uint64_t            mSize;
         MtpObjectFormat     mFormat;
         int                 mFD;
@@ -95,14 +95,14 @@
             close(mFD);
         }
     };
-    Vector<ObjectEdit*>  mObjectEditList;
+    std::vector<ObjectEdit*>  mObjectEditList;
 
 public:
                         MtpServer(IMtpDatabase* database, int controlFd, bool ptp,
-                                    const MtpString& deviceInfoManufacturer,
-                                    const MtpString& deviceInfoModel,
-                                    const MtpString& deviceInfoDeviceVersion,
-                                    const MtpString& deviceInfoSerialNumber);
+                                    const char *deviceInfoManufacturer,
+                                    const char *deviceInfoModel,
+                                    const char *deviceInfoDeviceVersion,
+                                    const char *deviceInfoSerialNumber);
     virtual             ~MtpServer();
 
     MtpStorage*         getStorage(MtpStorageID id);
@@ -122,7 +122,7 @@
     void                sendStoreRemoved(MtpStorageID id);
     void                sendEvent(MtpEventCode code, uint32_t param1);
 
-    void                addEditObject(MtpObjectHandle handle, MtpString& path,
+    void                addEditObject(MtpObjectHandle handle, MtpStringBuffer& path,
                                 uint64_t size, MtpObjectFormat format, int fd);
     ObjectEdit*         getEditObject(MtpObjectHandle handle);
     void                removeEditObject(MtpObjectHandle handle);
diff --git a/media/mtp/MtpStorage.h b/media/mtp/MtpStorage.h
index cb7e333..e9518dd 100644
--- a/media/mtp/MtpStorage.h
+++ b/media/mtp/MtpStorage.h
@@ -17,6 +17,7 @@
 #ifndef _MTP_STORAGE_H
 #define _MTP_STORAGE_H
 
+#include "MtpStringBuffer.h"
 #include "MtpTypes.h"
 #include "mtp.h"
 
@@ -28,8 +29,8 @@
 
 private:
     MtpStorageID            mStorageID;
-    MtpString               mFilePath;
-    MtpString               mDescription;
+    MtpStringBuffer         mFilePath;
+    MtpStringBuffer         mDescription;
     uint64_t                mMaxCapacity;
     uint64_t                mMaxFileSize;
     bool                    mRemovable;
diff --git a/media/mtp/MtpStringBuffer.cpp b/media/mtp/MtpStringBuffer.cpp
index df04694..cd379bf 100644
--- a/media/mtp/MtpStringBuffer.cpp
+++ b/media/mtp/MtpStringBuffer.cpp
@@ -16,168 +16,97 @@
 
 #define LOG_TAG "MtpStringBuffer"
 
-#include <string.h>
+#include <codecvt>
+#include <locale>
+#include <string>
+#include <vector>
 
 #include "MtpDataPacket.h"
 #include "MtpStringBuffer.h"
 
-namespace android {
+namespace {
 
-MtpStringBuffer::MtpStringBuffer()
-    :   mCharCount(0),
-        mByteCount(1)
-{
-    mBuffer[0] = 0;
+std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> gConvert;
+
+static std::string utf16ToUtf8(std::u16string input_str) {
+    return gConvert.to_bytes(input_str);
 }
 
+static std::u16string utf8ToUtf16(std::string input_str) {
+    return gConvert.from_bytes(input_str);
+}
+
+} // namespace
+
+namespace android {
+
 MtpStringBuffer::MtpStringBuffer(const char* src)
-    :   mCharCount(0),
-        mByteCount(1)
 {
     set(src);
 }
 
 MtpStringBuffer::MtpStringBuffer(const uint16_t* src)
-    :   mCharCount(0),
-        mByteCount(1)
 {
     set(src);
 }
 
 MtpStringBuffer::MtpStringBuffer(const MtpStringBuffer& src)
-    :   mCharCount(src.mCharCount),
-        mByteCount(src.mByteCount)
 {
-    memcpy(mBuffer, src.mBuffer, mByteCount);
-}
-
-
-MtpStringBuffer::~MtpStringBuffer() {
+    mString = src.mString;
 }
 
 void MtpStringBuffer::set(const char* src) {
-    // count the characters
-    int count = 0;
-    char ch;
-    char* dest = (char*)mBuffer;
-
-    while ((ch = *src++) != 0 && count < MTP_STRING_MAX_CHARACTER_NUMBER) {
-        if ((ch & 0x80) == 0) {
-            // single byte character
-            *dest++ = ch;
-        } else if ((ch & 0xE0) == 0xC0) {
-            // two byte character
-            char ch1 = *src++;
-            if (! ch1) {
-                // last character was truncated, so ignore last byte
-                break;
-            }
-
-            *dest++ = ch;
-            *dest++ = ch1;
-        } else if ((ch & 0xF0) == 0xE0) {
-            // 3 byte char
-            char ch1 = *src++;
-            if (! ch1) {
-                // last character was truncated, so ignore last byte
-                break;
-            }
-            char ch2 = *src++;
-            if (! ch2) {
-                // last character was truncated, so ignore last byte
-                break;
-            }
-
-            *dest++ = ch;
-            *dest++ = ch1;
-            *dest++ = ch2;
-        }
-        count++;
-    }
-
-    *dest++ = 0;
-    mByteCount = dest - (char*)mBuffer;
-    mCharCount = count;
+    mString = std::string(src);
 }
 
 void MtpStringBuffer::set(const uint16_t* src) {
-    int count = 0;
-    uint16_t ch;
-    uint8_t* dest = mBuffer;
-
-    while ((ch = *src++) != 0 && count < MTP_STRING_MAX_CHARACTER_NUMBER) {
-        if (ch >= 0x0800) {
-            *dest++ = (uint8_t)(0xE0 | (ch >> 12));
-            *dest++ = (uint8_t)(0x80 | ((ch >> 6) & 0x3F));
-            *dest++ = (uint8_t)(0x80 | (ch & 0x3F));
-        } else if (ch >= 0x80) {
-            *dest++ = (uint8_t)(0xC0 | (ch >> 6));
-            *dest++ = (uint8_t)(0x80 | (ch & 0x3F));
-        } else {
-            *dest++ = ch;
-        }
-        count++;
-    }
-    *dest++ = 0;
-    mCharCount = count;
-    mByteCount = dest - mBuffer;
+    mString = utf16ToUtf8(std::u16string((const char16_t*)src));
 }
 
 bool MtpStringBuffer::readFromPacket(MtpDataPacket* packet) {
     uint8_t count;
     if (!packet->getUInt8(count))
         return false;
+    if (count == 0)
+        return true;
 
-    uint8_t* dest = mBuffer;
+    std::vector<char16_t> buffer(count);
     for (int i = 0; i < count; i++) {
         uint16_t ch;
-
         if (!packet->getUInt16(ch))
             return false;
-        if (ch >= 0x0800) {
-            *dest++ = (uint8_t)(0xE0 | (ch >> 12));
-            *dest++ = (uint8_t)(0x80 | ((ch >> 6) & 0x3F));
-            *dest++ = (uint8_t)(0x80 | (ch & 0x3F));
-        } else if (ch >= 0x80) {
-            *dest++ = (uint8_t)(0xC0 | (ch >> 6));
-            *dest++ = (uint8_t)(0x80 | (ch & 0x3F));
-        } else {
-            *dest++ = ch;
-        }
+        buffer[i] = ch;
     }
-    *dest++ = 0;
-    mCharCount = count;
-    mByteCount = dest - mBuffer;
+    if (buffer[count-1] != '\0') {
+        ALOGE("Mtp string not null terminated\n");
+        return false;
+    }
+    mString = utf16ToUtf8(std::u16string(buffer.data()));
     return true;
 }
 
 void MtpStringBuffer::writeToPacket(MtpDataPacket* packet) const {
-    int count = mCharCount;
-    const uint8_t* src = mBuffer;
-    packet->putUInt8(count > 0 ? count + 1 : 0);
+    std::u16string src16 = utf8ToUtf16(mString);
+    int count = src16.length();
 
-    // expand utf8 to 16 bit chars
-    for (int i = 0; i < count; i++) {
-        uint16_t ch;
-        uint16_t ch1 = *src++;
-        if ((ch1 & 0x80) == 0) {
-            // single byte character
-            ch = ch1;
-        } else if ((ch1 & 0xE0) == 0xC0) {
-            // two byte character
-            uint16_t ch2 = *src++;
-            ch = ((ch1 & 0x1F) << 6) | (ch2 & 0x3F);
-        } else {
-            // three byte character
-            uint16_t ch2 = *src++;
-            uint16_t ch3 = *src++;
-            ch = ((ch1 & 0x0F) << 12) | ((ch2 & 0x3F) << 6) | (ch3 & 0x3F);
+    if (count == 0) {
+        packet->putUInt8(0);
+        return;
+    }
+    packet->putUInt8(std::min(count + 1, MTP_STRING_MAX_CHARACTER_NUMBER));
+
+    int i = 0;
+    for (char16_t &c : src16) {
+        if (i == MTP_STRING_MAX_CHARACTER_NUMBER - 1) {
+            // Leave a slot for null termination.
+            ALOGI("Mtp truncating long string\n");
+            break;
         }
-        packet->putUInt16(ch);
+        packet->putUInt16(c);
+        i++;
     }
     // only terminate with zero if string is not empty
-    if (count > 0)
-        packet->putUInt16(0);
+    packet->putUInt16(0);
 }
 
 }  // namespace android
diff --git a/media/mtp/MtpStringBuffer.h b/media/mtp/MtpStringBuffer.h
index bcf2a48..4cec58a 100644
--- a/media/mtp/MtpStringBuffer.h
+++ b/media/mtp/MtpStringBuffer.h
@@ -17,7 +17,9 @@
 #ifndef _MTP_STRING_BUFFER_H
 #define _MTP_STRING_BUFFER_H
 
+#include <log/log.h>
 #include <stdint.h>
+#include <string>
 
 // Max Character number of a MTP String
 #define MTP_STRING_MAX_CHARACTER_NUMBER             255
@@ -30,31 +32,39 @@
 class MtpStringBuffer {
 
 private:
-    // mBuffer contains string in UTF8 format
-    // maximum 3 bytes/character, with 1 extra for zero termination
-    uint8_t         mBuffer[MTP_STRING_MAX_CHARACTER_NUMBER * 3 + 1];
-    int             mCharCount;
-    int             mByteCount;
+    std::string     mString;
 
 public:
-                    MtpStringBuffer();
+                    MtpStringBuffer() {};
+                    ~MtpStringBuffer() {};
+
     explicit        MtpStringBuffer(const char* src);
     explicit        MtpStringBuffer(const uint16_t* src);
                     MtpStringBuffer(const MtpStringBuffer& src);
-    virtual         ~MtpStringBuffer();
 
     void            set(const char* src);
     void            set(const uint16_t* src);
 
+    inline void     append(const char* other);
+    inline void     append(MtpStringBuffer &other);
+
     bool            readFromPacket(MtpDataPacket* packet);
     void            writeToPacket(MtpDataPacket* packet) const;
 
-    inline int      getCharCount() const { return mCharCount; }
-    inline int      getByteCount() const { return mByteCount; }
+    inline bool     isEmpty() const { return mString.empty(); }
+    inline int      size() const { return mString.length(); }
 
-	inline operator const char*() const { return (const char *)mBuffer; }
+    inline operator const char*() const { return mString.c_str(); }
 };
 
+inline void MtpStringBuffer::append(const char* other) {
+    mString += other;
+}
+
+inline void MtpStringBuffer::append(MtpStringBuffer &other) {
+    mString += other.mString;
+}
+
 }; // namespace android
 
 #endif // _MTP_STRING_BUFFER_H
diff --git a/media/mtp/MtpTypes.h b/media/mtp/MtpTypes.h
index c749c66..e6ac23c 100644
--- a/media/mtp/MtpTypes.h
+++ b/media/mtp/MtpTypes.h
@@ -18,8 +18,7 @@
 #define _MTP_TYPES_H
 
 #include <stdint.h>
-#include "utils/String8.h"
-#include "utils/Vector.h"
+#include <vector>
 
 namespace android {
 
@@ -51,18 +50,18 @@
 class MtpDevice;
 class MtpProperty;
 
-typedef Vector<MtpStorage *> MtpStorageList;
-typedef Vector<MtpDevice*> MtpDeviceList;
-typedef Vector<MtpProperty*> MtpPropertyList;
+typedef std::vector<MtpStorage *> MtpStorageList;
+typedef std::vector<MtpDevice*> MtpDeviceList;
+typedef std::vector<MtpProperty*> MtpPropertyList;
 
-typedef Vector<uint8_t> UInt8List;
-typedef Vector<uint16_t> UInt16List;
-typedef Vector<uint32_t> UInt32List;
-typedef Vector<uint64_t> UInt64List;
-typedef Vector<int8_t> Int8List;
-typedef Vector<int16_t> Int16List;
-typedef Vector<int32_t> Int32List;
-typedef Vector<int64_t> Int64List;
+typedef std::vector<uint8_t> UInt8List;
+typedef std::vector<uint16_t> UInt16List;
+typedef std::vector<uint32_t> UInt32List;
+typedef std::vector<uint64_t> UInt64List;
+typedef std::vector<int8_t> Int8List;
+typedef std::vector<int16_t> Int16List;
+typedef std::vector<int32_t> Int32List;
+typedef std::vector<int64_t> Int64List;
 
 typedef UInt16List MtpObjectPropertyList;
 typedef UInt16List MtpDevicePropertyList;
@@ -71,8 +70,6 @@
 typedef UInt16List MtpObjectPropertyList;
 typedef UInt32List MtpStorageIDList;
 
-typedef String8    MtpString;
-
 enum UrbPacketDivisionMode {
     // First packet only contains a header.
     FIRST_PACKET_ONLY_HEADER,
diff --git a/media/mtp/tests/MtpFfsHandle_test.cpp b/media/mtp/tests/MtpFfsHandle_test.cpp
index 2174893..d11fe07 100644
--- a/media/mtp/tests/MtpFfsHandle_test.cpp
+++ b/media/mtp/tests/MtpFfsHandle_test.cpp
@@ -23,7 +23,7 @@
 #include <random>
 #include <string>
 #include <unistd.h>
-#include <utils/Log.h>
+#include <log/log.h>
 
 #include "MtpDescriptors.h"
 #include "MtpFfsHandle.h"
diff --git a/media/mtp/tests/PosixAsyncIO_test.cpp b/media/mtp/tests/PosixAsyncIO_test.cpp
index 63b9a35..9e337aa 100644
--- a/media/mtp/tests/PosixAsyncIO_test.cpp
+++ b/media/mtp/tests/PosixAsyncIO_test.cpp
@@ -20,7 +20,7 @@
 #include <gtest/gtest.h>
 #include <string>
 #include <unistd.h>
-#include <utils/Log.h>
+#include <log/log.h>
 
 #include "PosixAsyncIO.h"
 
diff --git a/packages/MediaComponents/res/drawable/custom_progress_thumb.xml b/packages/MediaComponents/res/drawable/custom_progress_thumb.xml
index 2e247f2..1a35970 100644
--- a/packages/MediaComponents/res/drawable/custom_progress_thumb.xml
+++ b/packages/MediaComponents/res/drawable/custom_progress_thumb.xml
@@ -17,6 +17,6 @@
     android:shape="oval" >
     <solid android:color="#ffffff" />
     <size
-        android:height="12dp"
-        android:width="12dp" />
+        android:height="@dimen/mcv2_custom_progress_thumb_size"
+        android:width="@dimen/mcv2_custom_progress_thumb_size" />
 </shape>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/drawable/ic_default_album_image.xml b/packages/MediaComponents/res/drawable/ic_default_album_image.xml
new file mode 100644
index 0000000..1cee643
--- /dev/null
+++ b/packages/MediaComponents/res/drawable/ic_default_album_image.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="512dp"
+    android:height="512dp"
+    android:viewportWidth="512"
+    android:viewportHeight="512">
+
+    <path
+        android:fillColor="#616161"
+        android:pathData="M 0 0 H 512 V 512 H 0 V 0 Z" />
+    <path
+        android:fillColor="#525252"
+        android:pathData="M256,151v123.14c-6.88-4.02-14.82-6.48-23.33-6.48 c-25.78,0-46.67,20.88-46.67,46.67c0,25.78,20.88,46.67,46.67,46.67s46.67-20.88,46.67-46.67V197.67H326V151H256z" />
+</vector>
diff --git a/packages/MediaComponents/res/layout/embedded_music.xml b/packages/MediaComponents/res/layout/embedded_music.xml
new file mode 100644
index 0000000..3e4d365
--- /dev/null
+++ b/packages/MediaComponents/res/layout/embedded_music.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="0.25"/>
+
+    <ImageView
+        android:id="@+id/album"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="0.5"
+        android:scaleType="fitCenter"
+        android:src="@drawable/ic_default_album_image" />
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="0.25"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/layout/full_landscape_music.xml b/packages/MediaComponents/res/layout/full_landscape_music.xml
new file mode 100644
index 0000000..8ce7058
--- /dev/null
+++ b/packages/MediaComponents/res/layout/full_landscape_music.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#B300FF00"
+    android:orientation="horizontal">
+
+    <LinearLayout
+        android:id="@+id/music_image"
+        style="@style/FullMusicLandscape.Image">
+
+        <ImageView
+            android:id="@+id/album"
+            android:layout_width="@dimen/mcv2_full_album_image_landscape_size"
+            android:layout_height="@dimen/mcv2_full_album_image_landscape_size"
+            android:src="@drawable/ic_default_album_image"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/music_text"
+        style="@style/FullMusicLandscape.Text">
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/mcv2_music_title_unknown_text"
+            android:textSize="20sp"
+            android:textStyle="bold"
+            android:textColor="#FFFFFF" />
+        <TextView
+            android:id="@+id/artist"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/mcv2_music_artist_unknown_text"
+            android:textSize="16sp"
+            android:textColor="#BBBBBB" />
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/layout/full_portrait_music.xml b/packages/MediaComponents/res/layout/full_portrait_music.xml
new file mode 100644
index 0000000..75f1bb3
--- /dev/null
+++ b/packages/MediaComponents/res/layout/full_portrait_music.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:id="@+id/music_image"
+        style="@style/FullMusicPortrait.Image">
+
+        <ImageView
+            android:id="@+id/album"
+            android:layout_width="@dimen/mcv2_full_album_image_portrait_size"
+            android:layout_height="@dimen/mcv2_full_album_image_portrait_size"
+            android:src="@drawable/ic_default_album_image"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/music_text"
+        style="@style/FullMusicPortrait.Text">
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="@dimen/mcv2_full_album_image_portrait_size"
+            android:layout_height="wrap_content"
+            android:text="@string/mcv2_music_title_unknown_text"
+            android:textSize="20sp"
+            android:textStyle="bold"
+            android:textColor="#FFFFFF" />
+        <TextView
+            android:id="@+id/artist"
+            android:layout_width="@dimen/mcv2_full_album_image_portrait_size"
+            android:layout_height="wrap_content"
+            android:text="@string/mcv2_music_artist_unknown_text"
+            android:textSize="16sp"
+            android:textColor="#BBBBBB" />
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/layout/media_controller.xml b/packages/MediaComponents/res/layout/media_controller.xml
index dfda840..4658f04 100644
--- a/packages/MediaComponents/res/layout/media_controller.xml
+++ b/packages/MediaComponents/res/layout/media_controller.xml
@@ -17,14 +17,12 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="#55000000"
     android:orientation="vertical"
     android:layoutDirection="ltr">
 
     <RelativeLayout
         android:id="@+id/title_bar"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:background="@layout/title_bar_gradient"
         style="@style/TitleBar">
 
         <LinearLayout
@@ -116,22 +114,51 @@
         android:layout_width="match_parent"
         android:layout_height="0dp"
         android:layout_weight="1"
-        android:gravity="center">
+        android:gravity="center"
+        android:orientation="vertical">
     </LinearLayout>
 
-    <SeekBar
-        android:id="@+id/mediacontroller_progress"
-        android:contentDescription="@string/mcv2_seek_bar_desc"
+    <LinearLayout
+        android:id="@+id/minimal_extra_view"
         android:layout_width="match_parent"
-        android:layout_height="12dp"
-        android:maxHeight="2dp"
-        android:minHeight="2dp"
-        android:padding="0dp"/>
+        android:layout_height="wrap_content"
+        android:gravity="right">
+
+        <ImageButton
+            android:id="@+id/fullscreen"
+            android:gravity="right"
+            style="@style/BottomBarButton.FullScreen" />
+    </LinearLayout>
 
     <RelativeLayout
         android:layout_width="match_parent"
+        android:layout_height="@dimen/mcv2_custom_progress_thumb_size">
+
+        <SeekBar
+            android:id="@+id/progress"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/mcv2_custom_progress_thumb_size"
+            android:contentDescription="@string/mcv2_seek_bar_desc"
+            android:padding="0dp"
+            android:maxHeight="@dimen/mcv2_custom_progress_max_size"
+            android:minHeight="@dimen/mcv2_custom_progress_max_size"
+            android:elevation="10dp"/>
+
+        <View
+            android:id="@+id/progress_buffer"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/mcv2_buffer_view_height"
+            android:layout_alignParentBottom="true"
+            android:background="@color/bottom_bar_background"
+            android:elevation="0dp"/>
+    </RelativeLayout>
+
+    <RelativeLayout
+        android:id="@+id/bottom_bar"
+        android:layout_width="match_parent"
         android:layout_height="44dp"
-        android:orientation="horizontal">
+        android:orientation="horizontal"
+        android:background="@color/bottom_bar_background">
 
         <LinearLayout
             android:id="@+id/bottom_bar_left"
diff --git a/packages/MediaComponents/res/layout/minimal_transport_controls.xml b/packages/MediaComponents/res/layout/minimal_transport_controls.xml
index 9ca3721..800c80b 100644
--- a/packages/MediaComponents/res/layout/minimal_transport_controls.xml
+++ b/packages/MediaComponents/res/layout/minimal_transport_controls.xml
@@ -18,8 +18,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center"
-    android:orientation="horizontal"
-    android:visibility="visible">
+    android:orientation="horizontal">
 
-    <ImageButton android:id="@+id/pause" style="@style/MinimalTransportControlsButton.Pause" />
+    <ImageButton android:id="@+id/pause" style="@style/MinimalTransportControlsButton" />
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/layout/title_bar_gradient.xml b/packages/MediaComponents/res/layout/title_bar_gradient.xml
new file mode 100644
index 0000000..ab1fc6e
--- /dev/null
+++ b/packages/MediaComponents/res/layout/title_bar_gradient.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <gradient
+        android:startColor="@color/title_bar_gradient_start"
+        android:endColor="@color/title_bar_gradient_end"
+        android:angle="-270" />
+</shape>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/values/colors.xml b/packages/MediaComponents/res/values/colors.xml
index 6a65ef5..e7bc299 100644
--- a/packages/MediaComponents/res/values/colors.xml
+++ b/packages/MediaComponents/res/values/colors.xml
@@ -19,4 +19,7 @@
     <color name="white">#ffffff</color>
     <color name="white_opacity_70">#B3ffffff</color>
     <color name="black_opacity_70">#B3000000</color>
+    <color name="title_bar_gradient_start">#50000000</color>
+    <color name="title_bar_gradient_end">#00000000</color>
+    <color name="bottom_bar_background">#40202020</color>
 </resources>
\ No newline at end of file
diff --git a/packages/MediaComponents/res/values/dimens.xml b/packages/MediaComponents/res/values/dimens.xml
index 8d72d40..2d7b022 100644
--- a/packages/MediaComponents/res/values/dimens.xml
+++ b/packages/MediaComponents/res/values/dimens.xml
@@ -62,5 +62,11 @@
     <dimen name="mcv2_minimal_icon_size">24dp</dimen>
     <dimen name="mcv2_icon_margin">10dp</dimen>
 
+    <dimen name="mcv2_full_album_image_portrait_size">232dp</dimen>
+    <dimen name="mcv2_full_album_image_landscape_size">176dp</dimen>
+
+    <dimen name="mcv2_custom_progress_max_size">2dp</dimen>
+    <dimen name="mcv2_custom_progress_thumb_size">12dp</dimen>
+    <dimen name="mcv2_buffer_view_height">5dp</dimen>
     <!-- TODO: adjust bottom bar view -->
 </resources>
diff --git a/packages/MediaComponents/res/values/strings.xml b/packages/MediaComponents/res/values/strings.xml
index aaceac8..2597a3b 100644
--- a/packages/MediaComponents/res/values/strings.xml
+++ b/packages/MediaComponents/res/values/strings.xml
@@ -129,6 +129,10 @@
     <string name="MediaControlView2_audio_track_number_text">
         Track <xliff:g id="audio_number" example="1">%1$s</xliff:g>
     </string>
+    <!-- Text for displaying unknown song title. -->
+    <string name="mcv2_music_title_unknown_text">Song title unknown</string>
+    <!-- Text for displaying unknown artist name. -->
+    <string name="mcv2_music_artist_unknown_text">Artist unknown</string>
 
     <!--Content Descriptions -->
     <string name="mcv2_back_button_desc">Back</string>
diff --git a/packages/MediaComponents/res/values/style.xml b/packages/MediaComponents/res/values/style.xml
index 0be04e6..5b9a8ee 100644
--- a/packages/MediaComponents/res/values/style.xml
+++ b/packages/MediaComponents/res/values/style.xml
@@ -84,18 +84,19 @@
 
     <style name="MinimalTransportControlsButton">
         <item name="android:background">@null</item>
+        <item name="android:layout_width">@dimen/mcv2_pause_icon_size</item>
+        <item name="android:layout_height">@dimen/mcv2_pause_icon_size</item>
+        <item name="android:layout_margin">@dimen/mcv2_icon_margin</item>
         <item name="android:scaleType">fitXY</item>
-    </style>
-
-    <style name="MinimalTransportControlsButton.Pause">
         <item name="android:src">@drawable/ic_pause_circle_filled</item>
-        <item name="android:layout_width">@dimen/mcv2_minimal_icon_size</item>
-        <item name="android:layout_height">@dimen/mcv2_minimal_icon_size</item>
         <item name="android:contentDescription">@string/mcv2_pause_button_desc</item>
     </style>
 
     <style name="TitleBar">
+        <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">46dp</item>
+        <item name="android:paddingStart">5dp</item>
+        <item name="android:paddingEnd">5dp</item>
     </style>
 
     <style name="TitleBarButton">
@@ -182,4 +183,39 @@
       <item name="android:src">@drawable/ic_high_quality</item>
       <item name="android:contentDescription">@string/mcv2_video_quality_button_desc</item>
     </style>
+
+    <style name="FullMusicPortrait">
+        <item name="android:layout_height">0dp</item>
+    </style>
+
+    <style name="FullMusicPortrait.Image">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_weight">0.6</item>
+        <item name="android:gravity">center</item>
+    </style>
+
+    <style name="FullMusicPortrait.Text">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_weight">0.4</item>
+        <item name="android:gravity">top|center</item>
+        <item name="android:orientation">vertical</item>
+    </style>
+
+    <style name="FullMusicLandscape">
+        <item name="android:layout_width">0dp</item>
+    </style>
+
+    <style name="FullMusicLandscape.Image">
+        <item name="android:layout_height">match_parent</item>
+        <item name="android:layout_weight">0.35</item>
+        <item name="android:gravity">center|right</item>
+    </style>
+
+    <style name="FullMusicLandscape.Text">
+        <item name="android:layout_height">match_parent</item>
+        <item name="android:layout_weight">0.65</item>
+        <item name="android:layout_marginLeft">24dp</item>
+        <item name="android:gravity">center|left</item>
+        <item name="android:orientation">vertical</item>
+    </style>
 </resources>
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index 4cdc41d..3aff150 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -16,7 +16,9 @@
 
 package com.android.widget;
 
+import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Point;
 import android.media.MediaMetadata;
 import android.media.session.MediaController;
 import android.media.session.PlaybackState;
@@ -31,6 +33,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowManager;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.Button;
@@ -102,6 +105,10 @@
     private static final int SETTINGS_MODE_MAIN = 5;
     private static final int PLAYBACK_SPEED_1x_INDEX = 3;
 
+    private static final int MEDIA_TYPE_DEFAULT = 0;
+    private static final int MEDIA_TYPE_MUSIC = 1;
+    private static final int MEDIA_TYPE_ADVERTISEMENT = 2;
+
     private static final int SIZE_TYPE_EMBEDDED = 0;
     private static final int SIZE_TYPE_FULL = 1;
     // TODO: add support for Minimal size type.
@@ -123,6 +130,7 @@
     private int mDuration;
     private int mPrevState;
     private int mPrevWidth;
+    private int mPrevHeight;
     private int mOriginalLeftBarWidth;
     private int mVideoTrackCount;
     private int mAudioTrackCount;
@@ -137,8 +145,8 @@
     private int mEmbeddedSettingsItemHeight;
     private int mFullSettingsItemHeight;
     private int mSettingsWindowMargin;
+    private int mMediaType;
     private int mSizeType;
-    private int mOrientation;
     private long mPlaybackActions;
     private boolean mDragging;
     private boolean mIsFullScreen;
@@ -148,9 +156,10 @@
     private boolean mSeekAvailable;
     private boolean mIsAdvertisement;
     private boolean mIsMute;
+    private boolean mNeedUXUpdate;
 
     // Relating to Title Bar View
-    private View mRoot;
+    private ViewGroup mRoot;
     private View mTitleBar;
     private TextView mTitleView;
     private View mAdExternalLink;
@@ -167,8 +176,15 @@
     private ImageButton mNextButton;
     private ImageButton mPrevButton;
 
+    // Relating to Minimal Extra View
+    private LinearLayout mMinimalExtraView;
+
     // Relating to Progress Bar View
     private ProgressBar mProgress;
+    private View mProgressBuffer;
+
+    // Relating to Bottom Bar View
+    private ViewGroup mBottomBar;
 
     // Relating to Bottom Bar Left View
     private ViewGroup mBottomBarLeftView;
@@ -334,28 +350,63 @@
     public void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure_impl(widthMeasureSpec, heightMeasureSpec);
 
-        if (mPrevWidth != mInstance.getMeasuredWidth()) {
-            int currWidth = mInstance.getMeasuredWidth();
+        // Update layout when this view's width changes in order to avoid any UI overlap between
+        // transport controls.
+        if (mPrevWidth != mInstance.getMeasuredWidth()
+                || mPrevHeight != mInstance.getMeasuredHeight() || mNeedUXUpdate) {
+            // Dismiss SettingsWindow if it is showing.
+            mSettingsWindow.dismiss();
 
-            int iconSize = mResources.getDimensionPixelSize(R.dimen.mcv2_full_icon_size);
-            int marginSize = mResources.getDimensionPixelSize(R.dimen.mcv2_icon_margin);
-            int bottomBarRightWidthMax = iconSize * 4 + marginSize * 8;
-
-            int fullWidth = mTransportControls.getWidth() + mTimeView.getWidth()
-                    + bottomBarRightWidthMax;
             // These views may not have been initialized yet.
             if (mTransportControls.getWidth() == 0 || mTimeView.getWidth() == 0) {
                 return;
             }
-            if (mSizeType == SIZE_TYPE_EMBEDDED && fullWidth <= currWidth) {
-                updateLayoutForSizeChange(SIZE_TYPE_FULL);
-            } else if (mSizeType == SIZE_TYPE_FULL && fullWidth > currWidth) {
-                updateLayoutForSizeChange(SIZE_TYPE_EMBEDDED);
+
+            int currWidth = mInstance.getMeasuredWidth();
+            int currHeight = mInstance.getMeasuredHeight();
+            WindowManager manager = (WindowManager) mInstance.getContext().getApplicationContext()
+                    .getSystemService(Context.WINDOW_SERVICE);
+            Point screenSize = new Point();
+            manager.getDefaultDisplay().getSize(screenSize);
+            int screenWidth = screenSize.x;
+            int screenHeight = screenSize.y;
+            int fullIconSize = mResources.getDimensionPixelSize(R.dimen.mcv2_full_icon_size);
+            int embeddedIconSize = mResources.getDimensionPixelSize(
+                    R.dimen.mcv2_embedded_icon_size);
+            int marginSize = mResources.getDimensionPixelSize(R.dimen.mcv2_icon_margin);
+
+            // TODO: add support for Advertisement Mode.
+            if (mMediaType == MEDIA_TYPE_DEFAULT) {
+                // Max number of icons inside BottomBarRightView for Music mode is 4.
+                int maxIconCount = 4;
+                updateLayout(maxIconCount, fullIconSize, embeddedIconSize, marginSize, currWidth,
+                        currHeight, screenWidth, screenHeight);
+            } else if (mMediaType == MEDIA_TYPE_MUSIC) {
+                if (mNeedUXUpdate) {
+                    // One-time operation for Music media type
+                    mBasicControls.removeView(mMuteButton);
+                    mExtraControls.addView(mMuteButton, 0);
+                    mVideoQualityButton.setVisibility(View.GONE);
+                    if (mFfwdButton != null) {
+                        mFfwdButton.setVisibility(View.GONE);
+                    }
+                    if (mRewButton != null) {
+                        mRewButton.setVisibility(View.GONE);
+                    }
+                }
+                mNeedUXUpdate = false;
+
+                // Max number of icons inside BottomBarRightView for Music mode is 3.
+                int maxIconCount = 3;
+                updateLayout(maxIconCount, fullIconSize, embeddedIconSize, marginSize, currWidth,
+                        currHeight, screenWidth, screenHeight);
             }
-            // Dismiss SettingsWindow if it is showing.
-            mSettingsWindow.dismiss();
             mPrevWidth = currWidth;
+            mPrevHeight = currHeight;
         }
+        // TODO: move this to a different location.
+        // Update title bar parameters in order to avoid overlap between title view and the right
+        // side of the title bar.
         updateTitleBarLayout();
     }
 
@@ -468,13 +519,14 @@
      * @return The controller view.
      * @hide This doesn't work as advertised
      */
-    protected View makeControllerView() {
-        View root = ApiHelper.inflateLibLayout(mInstance.getContext(), R.layout.media_controller);
+    protected ViewGroup makeControllerView() {
+        ViewGroup root = (ViewGroup) ApiHelper.inflateLibLayout(mInstance.getContext(),
+                R.layout.media_controller);
         initControllerView(root);
         return root;
     }
 
-    private void initControllerView(View v) {
+    private void initControllerView(ViewGroup v) {
         // Relating to Title Bar View
         mTitleBar = v.findViewById(R.id.title_bar);
         mTitleView = v.findViewById(R.id.title_text);
@@ -482,6 +534,7 @@
         mBackButton = v.findViewById(R.id.back);
         if (mBackButton != null) {
             mBackButton.setOnClickListener(mBackListener);
+            mBackButton.setVisibility(View.GONE);
         }
         mRouteButton = v.findViewById(R.id.cast);
 
@@ -490,8 +543,18 @@
         mTransportControls = inflateTransportControls(R.layout.embedded_transport_controls);
         mCenterView.addView(mTransportControls);
 
+        // Relating to Minimal Extra View
+        mMinimalExtraView = (LinearLayout) v.findViewById(R.id.minimal_extra_view);
+        LinearLayout.LayoutParams params =
+                (LinearLayout.LayoutParams) mMinimalExtraView.getLayoutParams();
+        int iconSize = mResources.getDimensionPixelSize(R.dimen.mcv2_embedded_icon_size);
+        int marginSize = mResources.getDimensionPixelSize(R.dimen.mcv2_icon_margin);
+        params.setMargins(0, (iconSize + marginSize * 2) * (-1), 0, 0);
+        mMinimalExtraView.setLayoutParams(params);
+        mMinimalExtraView.setVisibility(View.GONE);
+
         // Relating to Progress Bar View
-        mProgress = v.findViewById(R.id.mediacontroller_progress);
+        mProgress = v.findViewById(R.id.progress);
         if (mProgress != null) {
             if (mProgress instanceof SeekBar) {
                 SeekBar seeker = (SeekBar) mProgress;
@@ -501,6 +564,10 @@
             }
             mProgress.setMax(MAX_PROGRESS);
         }
+        mProgressBuffer = v.findViewById(R.id.progress_buffer);
+
+        // Relating to Bottom Bar View
+        mBottomBar = v.findViewById(R.id.bottom_bar);
 
         // Relating to Bottom Bar Left View
         mBottomBarLeftView = v.findViewById(R.id.bottom_bar_left);
@@ -757,11 +824,11 @@
                 return;
             }
             if (mDuration > 0) {
-                int newPosition = (int) (((long) mDuration * progress) / MAX_PROGRESS);
-                mControls.seekTo(newPosition);
+                int position = (int) (((long) mDuration * progress) / MAX_PROGRESS);
+                mControls.seekTo(position);
 
                 if (mCurrentTime != null) {
-                    mCurrentTime.setText(stringForTime(newPosition));
+                    mCurrentTime.setText(stringForTime(position));
                 }
             }
         }
@@ -862,7 +929,7 @@
             }
             Bundle args = new Bundle();
             args.putBoolean(ARGUMENT_KEY_FULLSCREEN, isEnteringFullScreen);
-            mController.sendCommand(MediaControlView2Impl.COMMAND_SET_FULLSCREEN, args, null);
+            mController.sendCommand(COMMAND_SET_FULLSCREEN, args, null);
 
             mIsFullScreen = isEnteringFullScreen;
         }
@@ -1040,6 +1107,34 @@
         }
     }
 
+    private void updateAudioMetadata() {
+        if (mMediaType != MEDIA_TYPE_MUSIC) {
+            return;
+        }
+
+        if (mMetadata != null) {
+            String titleText = "";
+            String artistText = "";
+            if (mMetadata.containsKey(MediaMetadata.METADATA_KEY_TITLE)) {
+                titleText = mMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
+            } else {
+                titleText = mResources.getString(R.string.mcv2_music_title_unknown_text);
+            }
+
+            if (mMetadata.containsKey(MediaMetadata.METADATA_KEY_ARTIST)) {
+                artistText = mMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
+            } else {
+                artistText = mResources.getString(R.string.mcv2_music_artist_unknown_text);
+            }
+
+            // Update title for Embedded size type
+            mTitleView.setText(titleText + " - " + artistText);
+
+            // Set to true to update layout inside onMeasure()
+            mNeedUXUpdate = true;
+        }
+    }
+
     private void updateLayout() {
         if (mIsAdvertisement) {
             mRewButton.setVisibility(View.GONE);
@@ -1071,38 +1166,135 @@
         }
     }
 
+    private void updateLayout(int maxIconCount, int fullIconSize, int embeddedIconSize,
+             int marginSize, int currWidth, int currHeight, int screenWidth, int screenHeight) {
+        int fullBottomBarRightWidthMax = fullIconSize * maxIconCount
+                + marginSize * (maxIconCount * 2);
+        int embeddedBottomBarRightWidthMax = embeddedIconSize * maxIconCount
+                + marginSize * (maxIconCount * 2);
+        int fullWidth = mTransportControls.getWidth() + mTimeView.getWidth()
+                + fullBottomBarRightWidthMax;
+        int embeddedWidth = mTimeView.getWidth() + embeddedBottomBarRightWidthMax;
+        int screenMaxLength = Math.max(screenWidth, screenHeight);
+
+        if (fullWidth > screenMaxLength) {
+            // TODO: screen may be smaller than the length needed for Full size.
+        }
+
+        boolean isFullSize = (mMediaType == MEDIA_TYPE_DEFAULT) ? (currWidth == screenMaxLength) :
+                (currWidth == screenWidth && currHeight == screenHeight);
+
+        if (isFullSize) {
+            if (mSizeType != SIZE_TYPE_FULL) {
+                updateLayoutForSizeChange(SIZE_TYPE_FULL);
+                if (mMediaType == MEDIA_TYPE_MUSIC) {
+                    mTitleView.setVisibility(View.GONE);
+                }
+            }
+        } else if (embeddedWidth <= currWidth) {
+            if (mSizeType != SIZE_TYPE_EMBEDDED) {
+                updateLayoutForSizeChange(SIZE_TYPE_EMBEDDED);
+                if (mMediaType == MEDIA_TYPE_MUSIC) {
+                    mTitleView.setVisibility(View.VISIBLE);
+                }
+            }
+        } else {
+            if (mSizeType != SIZE_TYPE_MINIMAL) {
+                updateLayoutForSizeChange(SIZE_TYPE_MINIMAL);
+                if (mMediaType == MEDIA_TYPE_MUSIC) {
+                    mTitleView.setVisibility(View.GONE);
+                }
+            }
+        }
+    }
+
     private void updateLayoutForSizeChange(int sizeType) {
         mSizeType = sizeType;
-        RelativeLayout.LayoutParams params =
+        RelativeLayout.LayoutParams timeViewParams =
                 (RelativeLayout.LayoutParams) mTimeView.getLayoutParams();
+        SeekBar seeker = (SeekBar) mProgress;
         switch (mSizeType) {
             case SIZE_TYPE_EMBEDDED:
+                // Relating to Title Bar
+                mTitleBar.setVisibility(View.VISIBLE);
+                mBackButton.setVisibility(View.GONE);
+
+                // Relating to Full Screen Button
+                mMinimalExtraView.setVisibility(View.GONE);
+                mFullScreenButton = mBottomBarRightView.findViewById(R.id.fullscreen);
+                mFullScreenButton.setOnClickListener(mFullScreenListener);
+
+                // Relating to Center View
+                mCenterView.removeAllViews();
                 mBottomBarLeftView.removeView(mTransportControls);
                 mBottomBarLeftView.setVisibility(View.GONE);
                 mTransportControls = inflateTransportControls(R.layout.embedded_transport_controls);
-                mCenterView.addView(mTransportControls, 0);
+                mCenterView.addView(mTransportControls);
 
-                if (params.getRule(RelativeLayout.LEFT_OF) != 0) {
-                    params.removeRule(RelativeLayout.LEFT_OF);
-                    params.addRule(RelativeLayout.RIGHT_OF, R.id.bottom_bar_left);
+                // Relating to Progress Bar
+                seeker.setThumb(mResources.getDrawable(R.drawable.custom_progress_thumb));
+                mProgressBuffer.setVisibility(View.VISIBLE);
+
+                // Relating to Bottom Bar
+                mBottomBar.setVisibility(View.VISIBLE);
+                if (timeViewParams.getRule(RelativeLayout.LEFT_OF) != 0) {
+                    timeViewParams.removeRule(RelativeLayout.LEFT_OF);
+                    timeViewParams.addRule(RelativeLayout.RIGHT_OF, R.id.bottom_bar_left);
                 }
                 break;
             case SIZE_TYPE_FULL:
-                mCenterView.removeView(mTransportControls);
+                // Relating to Title Bar
+                mTitleBar.setVisibility(View.VISIBLE);
+                mBackButton.setVisibility(View.VISIBLE);
+
+                // Relating to Full Screen Button
+                mMinimalExtraView.setVisibility(View.GONE);
+                mFullScreenButton = mBottomBarRightView.findViewById(R.id.fullscreen);
+                mFullScreenButton.setOnClickListener(mFullScreenListener);
+
+                // Relating to Center View
+                mCenterView.removeAllViews();
+                mBottomBarLeftView.removeView(mTransportControls);
                 mTransportControls = inflateTransportControls(R.layout.full_transport_controls);
                 mBottomBarLeftView.addView(mTransportControls, 0);
                 mBottomBarLeftView.setVisibility(View.VISIBLE);
 
-                if (params.getRule(RelativeLayout.RIGHT_OF) != 0) {
-                    params.removeRule(RelativeLayout.RIGHT_OF);
-                    params.addRule(RelativeLayout.LEFT_OF, R.id.bottom_bar_right);
+                // Relating to Progress Bar
+                seeker.setThumb(mResources.getDrawable(R.drawable.custom_progress_thumb));
+                mProgressBuffer.setVisibility(View.VISIBLE);
+
+                // Relating to Bottom Bar
+                mBottomBar.setVisibility(View.VISIBLE);
+                if (timeViewParams.getRule(RelativeLayout.RIGHT_OF) != 0) {
+                    timeViewParams.removeRule(RelativeLayout.RIGHT_OF);
+                    timeViewParams.addRule(RelativeLayout.LEFT_OF, R.id.bottom_bar_right);
                 }
                 break;
             case SIZE_TYPE_MINIMAL:
-                // TODO: implement
+                // Relating to Title Bar
+                mTitleBar.setVisibility(View.GONE);
+                mBackButton.setVisibility(View.GONE);
+
+                // Relating to Full Screen Button
+                mMinimalExtraView.setVisibility(View.VISIBLE);
+                mFullScreenButton = mMinimalExtraView.findViewById(R.id.fullscreen);
+                mFullScreenButton.setOnClickListener(mFullScreenListener);
+
+                // Relating to Center View
+                mCenterView.removeAllViews();
+                mBottomBarLeftView.removeView(mTransportControls);
+                mTransportControls = inflateTransportControls(R.layout.minimal_transport_controls);
+                mCenterView.addView(mTransportControls);
+
+                // Relating to Progress Bar
+                seeker.setThumb(null);
+                mProgressBuffer.setVisibility(View.GONE);
+
+                // Relating to Bottom Bar
+                mBottomBar.setVisibility(View.GONE);
                 break;
         }
-        mTimeView.setLayoutParams(params);
+        mTimeView.setLayoutParams(timeViewParams);
 
         if (isPlaying()) {
             mPlayPauseButton.setImageDrawable(
@@ -1115,6 +1307,14 @@
             mPlayPauseButton.setContentDescription(
                     mResources.getString(R.string.mcv2_play_button_desc));
         }
+
+        if (mIsFullScreen) {
+            mFullScreenButton.setImageDrawable(
+                    mResources.getDrawable(R.drawable.ic_fullscreen_exit, null));
+        } else {
+            mFullScreenButton.setImageDrawable(
+                    mResources.getDrawable(R.drawable.ic_fullscreen, null));
+        }
     }
 
     private View inflateTransportControls(int layoutId) {
@@ -1127,10 +1327,16 @@
         mFfwdButton = v.findViewById(R.id.ffwd);
         if (mFfwdButton != null) {
             mFfwdButton.setOnClickListener(mFfwdListener);
+            if (mMediaType == MEDIA_TYPE_MUSIC) {
+                mFfwdButton.setVisibility(View.GONE);
+            }
         }
         mRewButton = v.findViewById(R.id.rew);
         if (mRewButton != null) {
             mRewButton.setOnClickListener(mRewListener);
+            if (mMediaType == MEDIA_TYPE_MUSIC) {
+                mRewButton.setVisibility(View.GONE);
+            }
         }
         // TODO: Add support for Next and Previous buttons
         mNextButton = v.findViewById(R.id.next);
@@ -1250,11 +1456,17 @@
                 if ((newActions & PlaybackState.ACTION_PAUSE) != 0) {
                     mPlayPauseButton.setVisibility(View.VISIBLE);
                 }
-                if ((newActions & PlaybackState.ACTION_REWIND) != 0) {
-                    mRewButton.setVisibility(View.VISIBLE);
+                if ((newActions & PlaybackState.ACTION_REWIND) != 0
+                        && mMediaType != MEDIA_TYPE_MUSIC) {
+                    if (mRewButton != null) {
+                        mRewButton.setVisibility(View.VISIBLE);
+                    }
                 }
-                if ((newActions & PlaybackState.ACTION_FAST_FORWARD) != 0) {
-                    mFfwdButton.setVisibility(View.VISIBLE);
+                if ((newActions & PlaybackState.ACTION_FAST_FORWARD) != 0
+                        && mMediaType != MEDIA_TYPE_MUSIC) {
+                    if (mFfwdButton != null) {
+                        mFfwdButton.setVisibility(View.VISIBLE);
+                    }
                 }
                 if ((newActions & PlaybackState.ACTION_SEEK_TO) != 0) {
                     mSeekAvailable = true;
@@ -1295,6 +1507,7 @@
             mMetadata = metadata;
             updateDuration();
             updateTitle();
+            updateAudioMetadata();
         }
 
         @Override
@@ -1321,6 +1534,9 @@
                         mAudioTrackList.add(mResources.getString(
                                 R.string.MediaControlView2_audio_track_none_text));
                     }
+                    if (mVideoTrackCount == 0 && mAudioTrackCount > 0) {
+                        mMediaType = MEDIA_TYPE_MUSIC;
+                    }
 
                     mSubtitleTrackCount = extras.getInt(KEY_SUBTITLE_TRACK_COUNT);
                     mSubtitleDescriptionsList = new ArrayList<String>();
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 46ae359..b2acc26 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -17,6 +17,13 @@
 package com.android.widget;
 
 import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Point;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.media.AudioAttributes;
 import android.media.AudioFocusRequest;
 import android.media.AudioManager;
@@ -29,6 +36,7 @@
 import android.media.SubtitleData;
 import android.media.MediaItem2;
 import android.media.MediaMetadata2;
+import android.media.MediaMetadataRetriever;
 import android.media.Metadata;
 import android.media.PlaybackParams;
 import android.media.TimedText;
@@ -45,19 +53,26 @@
 import android.os.ResultReceiver;
 import android.support.annotation.Nullable;
 import android.util.AttributeSet;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Pair;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
+import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
+import android.widget.ImageView;
 import android.widget.MediaControlView2;
+import android.widget.TextView;
 import android.widget.VideoView2;
 
+import com.android.internal.graphics.palette.Palette;
 import com.android.media.RoutePlayer;
 import com.android.media.subtitle.ClosedCaptionRenderer;
 import com.android.media.subtitle.SubtitleController;
 import com.android.media.subtitle.SubtitleTrack;
+import com.android.media.update.ApiHelper;
+import com.android.media.update.R;
 import com.android.support.mediarouter.media.MediaItemStatus;
 import com.android.support.mediarouter.media.MediaControlIntent;
 import com.android.support.mediarouter.media.MediaRouter;
@@ -87,6 +102,11 @@
     private static final int INVALID_TRACK_INDEX = -1;
     private static final float INVALID_SPEED = 0f;
 
+    private static final int SIZE_TYPE_EMBEDDED = 0;
+    private static final int SIZE_TYPE_FULL = 1;
+    // TODO: add support for Minimal size type.
+    private static final int SIZE_TYPE_MINIMAL = 2;
+
     private AccessibilityManager mAccessibilityManager;
     private AudioManager mAudioManager;
     private AudioAttributes mAudioAttributes;
@@ -107,10 +127,24 @@
     private MediaController mMediaController;
     private Metadata mMetadata;
     private MediaMetadata2 mMediaMetadata;
+    private MediaMetadataRetriever mRetriever;
     private boolean mNeedUpdateMediaType;
     private Bundle mMediaTypeData;
     private String mTitle;
 
+    // TODO: move music view inside SurfaceView/TextureView or implement VideoViewInterface.
+    private WindowManager mManager;
+    private Resources mResources;
+    private View mMusicView;
+    private Drawable mMusicAlbumDrawable;
+    private String mMusicTitleText;
+    private String mMusicArtistText;
+    private boolean mIsMusicMediaType;
+    private int mPrevWidth;
+    private int mPrevHeight;
+    private int mDominantColor;
+    private int mSizeType;
+
     private PlaybackState.Builder mStateBuilder;
     private List<PlaybackState.CustomAction> mCustomActionList;
     private int mTargetState = STATE_IDLE;
@@ -259,10 +293,8 @@
         mInstance.addView(mSurfaceView);
         mCurrentView = mSurfaceView;
 
-        LayoutParams subtitleParams = new LayoutParams(LayoutParams.MATCH_PARENT,
-                LayoutParams.MATCH_PARENT);
         mSubtitleView = new SubtitleView(mInstance.getContext());
-        mSubtitleView.setLayoutParams(subtitleParams);
+        mSubtitleView.setLayoutParams(params);
         mSubtitleView.setBackgroundColor(0);
         mInstance.addView(mSubtitleView);
 
@@ -492,6 +524,14 @@
         // TODO: remove this after moving MediaSession creating code inside initializing VideoView2
         if (mCurrentState == STATE_PREPARED) {
             extractTracks();
+            extractMetadata();
+            extractAudioMetadata();
+            if (mNeedUpdateMediaType) {
+                mMediaSession.sendSessionEvent(
+                        MediaControlView2Impl.EVENT_UPDATE_MEDIA_TYPE_STATUS,
+                        mMediaTypeData);
+                mNeedUpdateMediaType = false;
+            }
         }
     }
 
@@ -516,7 +556,9 @@
                     + ", mTargetState=" + mTargetState);
         }
         if (ev.getAction() == MotionEvent.ACTION_UP && mMediaControlView != null) {
-            toggleMediaControlViewVisibility();
+            if (!mIsMusicMediaType || mSizeType != SIZE_TYPE_FULL) {
+                toggleMediaControlViewVisibility();
+            }
         }
 
         return super.onTouchEvent_impl(ev);
@@ -525,7 +567,9 @@
     @Override
     public boolean onTrackballEvent_impl(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_UP && mMediaControlView != null) {
-            toggleMediaControlViewVisibility();
+            if (!mIsMusicMediaType || mSizeType != SIZE_TYPE_FULL) {
+                toggleMediaControlViewVisibility();
+            }
         }
 
         return super.onTrackballEvent_impl(ev);
@@ -537,6 +581,48 @@
         return super.dispatchTouchEvent_impl(ev);
     }
 
+    @Override
+    public void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure_impl(widthMeasureSpec, heightMeasureSpec);
+
+        if (mIsMusicMediaType) {
+            if (mPrevWidth != mInstance.getMeasuredWidth()
+                    || mPrevHeight != mInstance.getMeasuredHeight()) {
+                int currWidth = mInstance.getMeasuredWidth();
+                int currHeight = mInstance.getMeasuredHeight();
+                Point screenSize = new Point();
+                mManager.getDefaultDisplay().getSize(screenSize);
+                int screenWidth = screenSize.x;
+                int screenHeight = screenSize.y;
+
+                if (currWidth == screenWidth && currHeight == screenHeight) {
+                    int orientation = retrieveOrientation();
+                    if (orientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
+                        inflateMusicView(R.layout.full_landscape_music);
+                    } else {
+                        inflateMusicView(R.layout.full_portrait_music);
+                    }
+
+                    if (mSizeType != SIZE_TYPE_FULL) {
+                        mSizeType = SIZE_TYPE_FULL;
+                        // Remove existing mFadeOut callback
+                        mMediaControlView.removeCallbacks(mFadeOut);
+                        mMediaControlView.setVisibility(View.VISIBLE);
+                    }
+                } else {
+                    if (mSizeType != SIZE_TYPE_EMBEDDED) {
+                        mSizeType = SIZE_TYPE_EMBEDDED;
+                        inflateMusicView(R.layout.embedded_music);
+                        // Add new mFadeOut callback
+                        mMediaControlView.postDelayed(mFadeOut, mShowControllerIntervalMs);
+                    }
+                }
+                mPrevWidth = currWidth;
+                mPrevHeight = currHeight;
+            }
+        }
+    }
+
     ///////////////////////////////////////////////////
     // Implements VideoViewInterface.SurfaceListener
     ///////////////////////////////////////////////////
@@ -663,6 +749,8 @@
             if (scheme != null && scheme.equals("file")) {
                 mTitle = uri.getLastPathSegment();
             }
+            mRetriever = new MediaMetadataRetriever();
+            mRetriever.setDataSource(mInstance.getContext(), uri);
 
             if (DEBUG) {
                 Log.d(TAG, "openVideo(). mCurrentState=" + mCurrentState
@@ -798,7 +886,8 @@
 
     private void showController() {
         // TODO: Decide what to show when the state is not in playback state
-        if (mMediaControlView == null || !isInPlaybackState()) {
+        if (mMediaControlView == null || !isInPlaybackState()
+                || (mIsMusicMediaType && mSizeType == SIZE_TYPE_FULL)) {
             return;
         }
         mMediaControlView.removeCallbacks(mFadeOut);
@@ -898,6 +987,9 @@
         if (mAudioTrackIndices.size() > 0) {
             mSelectedAudioTrackIndex = 0;
         }
+        if (mVideoTrackIndices.size() == 0 && mAudioTrackIndices.size() > 0) {
+            mIsMusicMediaType = true;
+        }
 
         Bundle data = new Bundle();
         data.putInt(MediaControlView2Impl.KEY_VIDEO_TRACK_COUNT, mVideoTrackIndices.size());
@@ -909,6 +1001,110 @@
         mMediaSession.sendSessionEvent(MediaControlView2Impl.EVENT_UPDATE_TRACK_STATUS, data);
     }
 
+    private void extractMetadata() {
+        // Get and set duration and title values as MediaMetadata for MediaControlView2
+        MediaMetadata.Builder builder = new MediaMetadata.Builder();
+        if (mMetadata != null && mMetadata.has(Metadata.TITLE)) {
+            mTitle = mMetadata.getString(Metadata.TITLE);
+        }
+        builder.putString(MediaMetadata.METADATA_KEY_TITLE, mTitle);
+        builder.putLong(
+                MediaMetadata.METADATA_KEY_DURATION, mMediaPlayer.getDuration());
+
+        if (mMediaSession != null) {
+            mMediaSession.setMetadata(builder.build());
+        }
+    }
+
+    private void extractAudioMetadata() {
+        if (!mIsMusicMediaType) {
+            return;
+        }
+
+        mResources = ApiHelper.getLibResources(mInstance.getContext());
+        mManager = (WindowManager) mInstance.getContext().getApplicationContext()
+                .getSystemService(Context.WINDOW_SERVICE);
+
+        byte[] album = mRetriever.getEmbeddedPicture();
+        if (album != null) {
+            Bitmap bitmap = BitmapFactory.decodeByteArray(album, 0, album.length);
+            mMusicAlbumDrawable = new BitmapDrawable(bitmap);
+
+            // TODO: replace with visualizer
+            Palette.generateAsync(bitmap, new Palette.PaletteAsyncListener() {
+                public void onGenerated(Palette palette) {
+                    // TODO: add dominant color for default album image.
+                    mDominantColor = palette.getDominantColor(0);
+                    if (mMusicView != null) {
+                        mMusicView.setBackgroundColor(mDominantColor);
+                    }
+                }
+            });
+        } else {
+            mMusicAlbumDrawable = mResources.getDrawable(R.drawable.ic_default_album_image);
+        }
+
+        String title = mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
+        if (title != null) {
+            mMusicTitleText = title;
+        } else {
+            mMusicTitleText = mResources.getString(R.string.mcv2_music_title_unknown_text);
+        }
+
+        String artist = mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
+        if (artist != null) {
+            mMusicArtistText = artist;
+        } else {
+            mMusicArtistText = mResources.getString(R.string.mcv2_music_artist_unknown_text);
+        }
+
+        // Send title and artist string to MediaControlView2
+        MediaMetadata.Builder builder = new MediaMetadata.Builder();
+        builder.putString(MediaMetadata.METADATA_KEY_TITLE, mMusicTitleText);
+        builder.putString(MediaMetadata.METADATA_KEY_ARTIST, mMusicArtistText);
+        mMediaSession.setMetadata(builder.build());
+
+        // Display Embedded mode as default
+        mInstance.removeView(mSurfaceView);
+        mInstance.removeView(mTextureView);
+        inflateMusicView(R.layout.embedded_music);
+    }
+
+    private int retrieveOrientation() {
+        DisplayMetrics dm = Resources.getSystem().getDisplayMetrics();
+        int width = dm.widthPixels;
+        int height = dm.heightPixels;
+
+        return (height > width) ?
+                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT :
+                ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+    }
+
+    private void inflateMusicView(int layoutId) {
+        mInstance.removeView(mMusicView);
+
+        View v = ApiHelper.inflateLibLayout(mInstance.getContext(), layoutId);
+        v.setBackgroundColor(mDominantColor);
+
+        ImageView albumView = v.findViewById(R.id.album);
+        if (albumView != null) {
+            albumView.setImageDrawable(mMusicAlbumDrawable);
+        }
+
+        TextView titleView = v.findViewById(R.id.title);
+        if (titleView != null) {
+            titleView.setText(mMusicTitleText);
+        }
+
+        TextView artistView = v.findViewById(R.id.artist);
+        if (artistView != null) {
+            artistView.setText(mMusicArtistText);
+        }
+
+        mMusicView = v;
+        mInstance.addView(mMusicView, 0);
+    }
+
     OnSubtitleDataListener mSubtitleListener =
             new OnSubtitleDataListener() {
                 @Override
@@ -994,6 +1190,14 @@
                     }
                 }
 
+                @Override
+                public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what,
+                        int status) {
+                    if (what == MediaPlayer2.CALL_COMPLETED_SEEK_TO && status == 0) {
+                        updatePlaybackState();
+                    }
+                }
+
                 private void onPrepared(MediaPlayer2 mp, DataSourceDesc dsd) {
                     if (DEBUG) {
                         Log.d(TAG, "OnPreparedListener(). mCurrentState=" + mCurrentState
@@ -1007,6 +1211,8 @@
                     // TODO: create MediaSession when initializing VideoView2
                     if (mMediaSession != null) {
                         extractTracks();
+                        extractMetadata();
+                        extractAudioMetadata();
                     }
 
                     if (mMediaControlView != null) {
@@ -1046,27 +1252,6 @@
                             mMediaController.getTransportControls().play();
                         }
                     }
-                    // Get and set duration and title values as MediaMetadata for MediaControlView2
-                    MediaMetadata.Builder builder = new MediaMetadata.Builder();
-                    if (mMetadata != null && mMetadata.has(Metadata.TITLE)) {
-                        mTitle = mMetadata.getString(Metadata.TITLE);
-                    }
-                    builder.putString(MediaMetadata.METADATA_KEY_TITLE, mTitle);
-                    builder.putLong(
-                            MediaMetadata.METADATA_KEY_DURATION, mMediaPlayer.getDuration());
-
-                    if (mMediaSession != null) {
-                        mMediaSession.setMetadata(builder.build());
-
-                        // TODO: merge this code with the above code when integrating with
-                        // MediaSession2.
-                        if (mNeedUpdateMediaType) {
-                            mMediaSession.sendSessionEvent(
-                                    MediaControlView2Impl.EVENT_UPDATE_MEDIA_TYPE_STATUS,
-                                    mMediaTypeData);
-                            mNeedUpdateMediaType = false;
-                        }
-                    }
                 }
 
                 private void onCompletion(MediaPlayer2 mp, DataSourceDesc dsd) {
@@ -1153,7 +1338,7 @@
 
         @Override
         public void onPlay() {
-            if (isInPlaybackState() && mCurrentView.hasAvailableSurface()) {
+            if (isInPlaybackState() && (mCurrentView.hasAvailableSurface() || mIsMusicMediaType)) {
                 if (isRemotePlayback()) {
                     mRoutePlayer.onPlay();
                 } else {
@@ -1200,7 +1385,6 @@
                 } else {
                     mMediaPlayer.seekTo(pos, MediaPlayer2.SEEK_PREVIOUS_SYNC);
                     mSeekWhenPrepared = 0;
-                    updatePlaybackState();
                 }
             } else {
                 mSeekWhenPrepared = pos;
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 9ed6d73..714d50f 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -904,7 +904,7 @@
     }
 
     // Make sure the UID is in an active state to use the camera
-    if (!mUidPolicy->isUidActive(callingUid)) {
+    if (!mUidPolicy->isUidActive(callingUid, String16(clientName8))) {
         ALOGE("Access Denial: can't use the camera from an idle UID pid=%d, uid=%d",
             clientPid, clientUid);
         return STATUS_ERROR_FMT(ERROR_DISABLED,
@@ -2423,12 +2423,12 @@
     }
 }
 
-bool CameraService::UidPolicy::isUidActive(uid_t uid) {
+bool CameraService::UidPolicy::isUidActive(uid_t uid, String16 callingPackage) {
     Mutex::Autolock _l(mUidLock);
-    return isUidActiveLocked(uid);
+    return isUidActiveLocked(uid, callingPackage);
 }
 
-bool CameraService::UidPolicy::isUidActiveLocked(uid_t uid) {
+bool CameraService::UidPolicy::isUidActiveLocked(uid_t uid, String16 callingPackage) {
     // Non-app UIDs are considered always active
     // If activity manager is unreachable, assume everything is active
     if (uid < FIRST_APPLICATION_UID || !mRegistered) {
@@ -2438,15 +2438,31 @@
     if (it != mOverrideUids.end()) {
         return it->second;
     }
-    return mActiveUids.find(uid) != mActiveUids.end();
+    bool active = mActiveUids.find(uid) != mActiveUids.end();
+    if (!active) {
+        // We want active UIDs to always access camera with their first attempt since
+        // there is no guarantee the app is robustly written and would retry getting
+        // the camera on failure. The inverse case is not a problem as we would take
+        // camera away soon once we get the callback that the uid is no longer active.
+        ActivityManager am;
+        // Okay to access with a lock held as UID changes are dispatched without
+        // a lock and we are a higher level component.
+        active = am.isUidActive(uid, callingPackage);
+        if (active) {
+            // Now that we found out the UID is actually active, cache that
+            mActiveUids.insert(uid);
+        }
+    }
+    return active;
 }
 
-void CameraService::UidPolicy::UidPolicy::addOverrideUid(uid_t uid, bool active) {
-    updateOverrideUid(uid, active, true);
+void CameraService::UidPolicy::UidPolicy::addOverrideUid(uid_t uid,
+        String16 callingPackage, bool active) {
+    updateOverrideUid(uid, callingPackage, active, true);
 }
 
-void CameraService::UidPolicy::removeOverrideUid(uid_t uid) {
-    updateOverrideUid(uid, false, false);
+void CameraService::UidPolicy::removeOverrideUid(uid_t uid, String16 callingPackage) {
+    updateOverrideUid(uid, callingPackage, false, false);
 }
 
 void CameraService::UidPolicy::binderDied(const wp<IBinder>& /*who*/) {
@@ -2456,17 +2472,18 @@
     mActiveUids.clear();
 }
 
-void CameraService::UidPolicy::updateOverrideUid(uid_t uid, bool active, bool insert) {
+void CameraService::UidPolicy::updateOverrideUid(uid_t uid, String16 callingPackage,
+        bool active, bool insert) {
     bool wasActive = false;
     bool isActive = false;
     {
         Mutex::Autolock _l(mUidLock);
-        wasActive = isUidActiveLocked(uid);
+        wasActive = isUidActiveLocked(uid, callingPackage);
         mOverrideUids.erase(uid);
         if (insert) {
             mOverrideUids.insert(std::pair<uid_t, bool>(uid, active));
         }
-        isActive = isUidActiveLocked(uid);
+        isActive = isUidActiveLocked(uid, callingPackage);
     }
     if (wasActive != isActive && !isActive) {
         sp<CameraService> service = mService.promote();
@@ -2999,7 +3016,7 @@
         ALOGE("Expected active or idle but got: '%s'", String8(args[2]).string());
         return BAD_VALUE;
     }
-    mUidPolicy->addOverrideUid(uid, active);
+    mUidPolicy->addOverrideUid(uid, args[1], active);
     return NO_ERROR;
 }
 
@@ -3011,7 +3028,7 @@
         dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
         return BAD_VALUE;
     }
-    mUidPolicy->removeOverrideUid(uid);
+    mUidPolicy->removeOverrideUid(uid, args[1]);
     return NO_ERROR;
 }
 
@@ -3023,7 +3040,7 @@
         dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
         return BAD_VALUE;
     }
-    if (mUidPolicy->isUidActive(uid)) {
+    if (mUidPolicy->isUidActive(uid, args[1])) {
         return dprintf(out, "active\n");
     } else {
         return dprintf(out, "idle\n");
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index a7a9264..8d4bcdb 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -526,20 +526,20 @@
         void registerSelf();
         void unregisterSelf();
 
-        bool isUidActive(uid_t uid);
+        bool isUidActive(uid_t uid, String16 callingPackage);
 
         void onUidGone(uid_t uid, bool disabled);
         void onUidActive(uid_t uid);
         void onUidIdle(uid_t uid, bool disabled);
 
-        void addOverrideUid(uid_t uid, bool active);
-        void removeOverrideUid(uid_t uid);
+        void addOverrideUid(uid_t uid, String16 callingPackage, bool active);
+        void removeOverrideUid(uid_t uid, String16 callingPackage);
 
         // IBinder::DeathRecipient implementation
         virtual void binderDied(const wp<IBinder> &who);
     private:
-        bool isUidActiveLocked(uid_t uid);
-        void updateOverrideUid(uid_t uid, bool active, bool insert);
+        bool isUidActiveLocked(uid_t uid, String16 callingPackage);
+        void updateOverrideUid(uid_t uid, String16 callingPackage, bool active, bool insert);
 
         Mutex mUidLock;
         bool mRegistered;