Merge "MediaControlView2: Add support for Minimal Mode" into pi-dev
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index 62b0ec9..fc00a2d 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -313,6 +313,7 @@
         case ACAMERA_TONEMAP_GAMMA:
         case ACAMERA_TONEMAP_PRESET_CURVE:
         case ACAMERA_BLACK_LEVEL_LOCK:
+        case ACAMERA_DISTORTION_CORRECTION_MODE:
             return true;
         default:
             return false;
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 346761c..5fd4886 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -70,6 +70,7 @@
     ACAMERA_REPROCESS,
     ACAMERA_DEPTH,
     ACAMERA_LOGICAL_MULTI_CAMERA,
+    ACAMERA_DISTORTION_CORRECTION,
     ACAMERA_SECTION_COUNT,
 
     ACAMERA_VENDOR = 0x8000
@@ -108,6 +109,9 @@
     ACAMERA_LOGICAL_MULTI_CAMERA_START
                                    = ACAMERA_LOGICAL_MULTI_CAMERA
                                                                 << 16,
+    ACAMERA_DISTORTION_CORRECTION_START
+                                   = ACAMERA_DISTORTION_CORRECTION
+                                                                << 16,
     ACAMERA_VENDOR_START           = ACAMERA_VENDOR            << 16
 } acamera_metadata_section_start_t;
 
@@ -5285,6 +5289,63 @@
             ACAMERA_LOGICAL_MULTI_CAMERA_START + 1,
     ACAMERA_LOGICAL_MULTI_CAMERA_END,
 
+    /**
+     * <p>Mode of operation for the lens distortion correction block.</p>
+     *
+     * <p>Type: byte (acamera_metadata_enum_android_distortion_correction_mode_t)</p>
+     *
+     * <p>This tag may appear in:
+     * <ul>
+     *   <li>ACameraMetadata from ACameraCaptureSession_captureCallback_result callbacks</li>
+     *   <li>ACaptureRequest</li>
+     * </ul></p>
+     *
+     * <p>The lens distortion correction block attempts to improve image quality by fixing
+     * radial, tangential, or other geometric aberrations in the camera device's optics.  If
+     * available, the ACAMERA_LENS_DISTORTION field documents the lens's distortion parameters.</p>
+     * <p>OFF means no distortion correction is done.</p>
+     * <p>FAST/HIGH_QUALITY both mean camera device determined distortion correction will be
+     * applied. HIGH_QUALITY mode indicates that the camera device will use the highest-quality
+     * correction algorithms, even if it slows down capture rate. FAST means the camera device
+     * will not slow down capture rate when applying correction. FAST may be the same as OFF if
+     * any correction at all would slow down capture rate.  Every output stream will have a
+     * similar amount of enhancement applied.</p>
+     * <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
+     * applied to any RAW output.  Metadata coordinates such as face rectangles or metering
+     * regions are also not affected by correction.</p>
+     * <p>Applications enabling distortion correction need to pay extra attention when converting
+     * image coordinates between corrected output buffers and the sensor array. For example, if
+     * the app supports tap-to-focus and enables correction, it then has to apply the distortion
+     * model described in ACAMERA_LENS_DISTORTION to the image buffer tap coordinates to properly
+     * calculate the tap position on the sensor active array to be used with
+     * ACAMERA_CONTROL_AF_REGIONS. The same applies in reverse to detected face rectangles if
+     * they need to be drawn on top of the corrected output buffers.</p>
+     *
+     * @see ACAMERA_CONTROL_AF_REGIONS
+     * @see ACAMERA_LENS_DISTORTION
+     */
+    ACAMERA_DISTORTION_CORRECTION_MODE =                        // byte (acamera_metadata_enum_android_distortion_correction_mode_t)
+            ACAMERA_DISTORTION_CORRECTION_START,
+    /**
+     * <p>List of distortion correction modes for ACAMERA_DISTORTION_CORRECTION_MODE that are
+     * supported by this camera device.</p>
+     *
+     * @see ACAMERA_DISTORTION_CORRECTION_MODE
+     *
+     * <p>Type: byte[n]</p>
+     *
+     * <p>This tag may appear in:
+     * <ul>
+     *   <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+     * </ul></p>
+     *
+     * <p>No device is required to support this API; such devices will always list only 'OFF'.
+     * All devices that support this API will list both FAST and HIGH_QUALITY.</p>
+     */
+    ACAMERA_DISTORTION_CORRECTION_AVAILABLE_MODES =             // byte[n]
+            ACAMERA_DISTORTION_CORRECTION_START + 1,
+    ACAMERA_DISTORTION_CORRECTION_END,
+
 } acamera_metadata_tag_t;
 
 /**
@@ -7682,6 +7743,29 @@
 } acamera_metadata_enum_android_logical_multi_camera_sensor_sync_type_t;
 
 
+// ACAMERA_DISTORTION_CORRECTION_MODE
+typedef enum acamera_metadata_enum_acamera_distortion_correction_mode {
+    /**
+     * <p>No distortion correction is applied.</p>
+     */
+    ACAMERA_DISTORTION_CORRECTION_MODE_OFF                           = 0,
+
+    /**
+     * <p>Lens distortion correction is applied without reducing frame rate
+     * relative to sensor output. It may be the same as OFF if distortion correction would
+     * reduce frame rate relative to sensor.</p>
+     */
+    ACAMERA_DISTORTION_CORRECTION_MODE_FAST                          = 1,
+
+    /**
+     * <p>High-quality distortion correction is applied, at the cost of
+     * possibly reduced frame rate relative to sensor output.</p>
+     */
+    ACAMERA_DISTORTION_CORRECTION_MODE_HIGH_QUALITY                  = 2,
+
+} acamera_metadata_enum_android_distortion_correction_mode_t;
+
+
 #endif /* __ANDROID_API__ >= 24 */
 
 __END_DECLS
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 873d836..a20f1f2 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -903,13 +903,15 @@
         case SET_MODE:
         case SET_MIC_MUTE:
         case SET_LOW_RAM_DEVICE:
-        case SYSTEM_READY:
-            if (IPCThreadState::self()->getCallingUid() >= AID_APP_START) {
+        case SYSTEM_READY: {
+            uid_t multiUserClientUid = IPCThreadState::self()->getCallingUid() % AID_USER_OFFSET;
+            if (multiUserClientUid >= AID_APP_START) {
                 ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
                       __func__, code, IPCThreadState::self()->getCallingPid(),
                       IPCThreadState::self()->getCallingUid());
                 return INVALID_OPERATION;
             }
+        } break;
         default:
             break;
     }
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 0b98502..a49b2cb 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -872,18 +872,33 @@
         case INIT_STREAM_VOLUME:
         case SET_STREAM_VOLUME:
         case REGISTER_POLICY_MIXES:
-        case SET_MASTER_MONO:
-            if (IPCThreadState::self()->getCallingUid() >= AID_APP_START) {
+        case SET_MASTER_MONO: {
+            uid_t multiUserClientUid = IPCThreadState::self()->getCallingUid() % AID_USER_OFFSET;
+            if (multiUserClientUid >= AID_APP_START) {
                 ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
                       __func__, code, IPCThreadState::self()->getCallingPid(),
                       IPCThreadState::self()->getCallingUid());
                 return INVALID_OPERATION;
             }
+        } break;
         default:
             break;
     }
 
-    TimeCheck check("IAudioPolicyService");
+    // FIXME: extend timeout for SET_DEVICE_CONNECTION_STATE and HANDLE_DEVICE_CONFIG_CHANGE
+    // while we investigate why BT A2DP device connection/disconnection can sometimes
+    // take more than 5 seconds
+    uint32_t timeoutMs = TimeCheck::kDefaultTimeOutMs;
+    switch (code) {
+        case SET_DEVICE_CONNECTION_STATE:
+        case HANDLE_DEVICE_CONFIG_CHANGE:
+            timeoutMs *= 2;
+            break;
+        default:
+            break;
+    }
+
+    TimeCheck check("IAudioPolicyService", timeoutMs);
 
     switch (code) {
         case SET_DEVICE_CONNECTION_STATE: {
diff --git a/media/mtp/IMtpHandle.h b/media/mtp/IMtpHandle.h
index c65bdd0..fd14b18 100644
--- a/media/mtp/IMtpHandle.h
+++ b/media/mtp/IMtpHandle.h
@@ -32,8 +32,7 @@
     virtual int sendEvent(mtp_event me) = 0;
 
     // Return 0 if operation is successful, or -1 else
-    virtual int start() = 0;
-    virtual int configure(bool ptp) = 0;
+    virtual int start(bool ptp) = 0;
 
     virtual void close() = 0;
 
diff --git a/media/mtp/MtpDescriptors.cpp b/media/mtp/MtpDescriptors.cpp
index d9b6060..4a336c8 100644
--- a/media/mtp/MtpDescriptors.cpp
+++ b/media/mtp/MtpDescriptors.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#include <android-base/logging.h>
+#include <sys/types.h>
+
 #include "MtpDescriptors.h"
 
 namespace android {
@@ -257,4 +260,24 @@
     .hs_descs = ptp_hs_descriptors,
 };
 
+bool writeDescriptors(int fd, bool ptp) {
+    ssize_t ret = TEMP_FAILURE_RETRY(write(fd,
+                &(ptp ? ptp_desc_v2 : mtp_desc_v2), sizeof(desc_v2)));
+    if (ret < 0) {
+        PLOG(ERROR) << fd << "Switching to V1 descriptor format";
+        ret = TEMP_FAILURE_RETRY(write(fd,
+                    &(ptp ? ptp_desc_v1 : mtp_desc_v1), sizeof(desc_v1)));
+        if (ret < 0) {
+            PLOG(ERROR) << fd << "Writing descriptors failed";
+            return false;
+        }
+    }
+    ret = TEMP_FAILURE_RETRY(write(fd, &mtp_strings, sizeof(mtp_strings)));
+    if (ret < 0) {
+        PLOG(ERROR) << fd << "Writing strings failed";
+        return false;
+    }
+    return true;
+}
+
 }; // namespace android
diff --git a/media/mtp/MtpDescriptors.h b/media/mtp/MtpDescriptors.h
index cfc3930..d600a24 100644
--- a/media/mtp/MtpDescriptors.h
+++ b/media/mtp/MtpDescriptors.h
@@ -23,6 +23,16 @@
 
 namespace android {
 
+constexpr char FFS_MTP_EP0[] = "/dev/usb-ffs/mtp/ep0";
+constexpr char FFS_MTP_EP_IN[] = "/dev/usb-ffs/mtp/ep1";
+constexpr char FFS_MTP_EP_OUT[] = "/dev/usb-ffs/mtp/ep2";
+constexpr char FFS_MTP_EP_INTR[] = "/dev/usb-ffs/mtp/ep3";
+
+constexpr char FFS_PTP_EP0[] = "/dev/usb-ffs/ptp/ep0";
+constexpr char FFS_PTP_EP_IN[] = "/dev/usb-ffs/ptp/ep1";
+constexpr char FFS_PTP_EP_OUT[] = "/dev/usb-ffs/ptp/ep2";
+constexpr char FFS_PTP_EP_INTR[] = "/dev/usb-ffs/ptp/ep3";
+
 constexpr int MAX_PACKET_SIZE_FS = 64;
 constexpr int MAX_PACKET_SIZE_HS = 512;
 constexpr int MAX_PACKET_SIZE_SS = 1024;
@@ -91,6 +101,8 @@
 extern const struct desc_v1 ptp_desc_v1;
 extern const struct functionfs_strings mtp_strings;
 
+bool writeDescriptors(int fd, bool ptp);
+
 }; // namespace android
 
 #endif // MTP_DESCRIPTORS_H
diff --git a/media/mtp/MtpDevHandle.cpp b/media/mtp/MtpDevHandle.cpp
index 6aa57ac..e8bdf80 100644
--- a/media/mtp/MtpDevHandle.cpp
+++ b/media/mtp/MtpDevHandle.cpp
@@ -60,7 +60,7 @@
     return ioctl(mFd, MTP_SEND_EVENT, reinterpret_cast<unsigned long>(&me));
 }
 
-int MtpDevHandle::start() {
+int MtpDevHandle::start(bool /* ptp */) {
     mFd.reset(TEMP_FAILURE_RETRY(open(mtp_dev_path, O_RDWR)));
     if (mFd == -1) return -1;
     return 0;
@@ -70,9 +70,4 @@
     mFd.reset();
 }
 
-int MtpDevHandle::configure(bool) {
-    // Nothing to do, driver can configure itself
-    return 0;
-}
-
 } // namespace android
diff --git a/media/mtp/MtpDevHandle.h b/media/mtp/MtpDevHandle.h
index b0480ed..740ac85 100644
--- a/media/mtp/MtpDevHandle.h
+++ b/media/mtp/MtpDevHandle.h
@@ -36,10 +36,8 @@
     int sendFile(mtp_file_range mfr);
     int sendEvent(mtp_event me);
 
-    int start();
+    int start(bool ptp);
     void close();
-
-    int configure(bool ptp);
 };
 
 } // namespace android
diff --git a/media/mtp/MtpFfsCompatHandle.cpp b/media/mtp/MtpFfsCompatHandle.cpp
index 3dd73f3..d2b342c 100644
--- a/media/mtp/MtpFfsCompatHandle.cpp
+++ b/media/mtp/MtpFfsCompatHandle.cpp
@@ -61,7 +61,8 @@
 
 namespace android {
 
-MtpFfsCompatHandle::MtpFfsCompatHandle() :
+MtpFfsCompatHandle::MtpFfsCompatHandle(int controlFd) :
+    MtpFfsHandle(controlFd),
     mMaxWrite(USB_FFS_MAX_WRITE),
     mMaxRead(USB_FFS_MAX_READ) {}
 
@@ -108,10 +109,8 @@
     return ret;
 }
 
-int MtpFfsCompatHandle::start() {
-    mLock.lock();
-
-    if (!openEndpoints())
+int MtpFfsCompatHandle::start(bool ptp) {
+    if (!openEndpoints(ptp))
         return -1;
 
     for (unsigned i = 0; i < NUM_IO_BUFS; i++) {
diff --git a/media/mtp/MtpFfsCompatHandle.h b/media/mtp/MtpFfsCompatHandle.h
index cd61482..5982d60 100644
--- a/media/mtp/MtpFfsCompatHandle.h
+++ b/media/mtp/MtpFfsCompatHandle.h
@@ -42,9 +42,9 @@
      * Open ffs endpoints and allocate necessary kernel and user memory.
      * Will sleep until endpoints are enabled, for up to 1 second.
      */
-    int start() override;
+    int start(bool ptp) override;
 
-    MtpFfsCompatHandle();
+    MtpFfsCompatHandle(int controlFd);
     ~MtpFfsCompatHandle();
 };
 
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 217e0c9..952b907 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -39,10 +39,6 @@
 
 namespace {
 
-constexpr char FFS_MTP_EP_IN[] = "/dev/usb-ffs/mtp/ep1";
-constexpr char FFS_MTP_EP_OUT[] = "/dev/usb-ffs/mtp/ep2";
-constexpr char FFS_MTP_EP_INTR[] = "/dev/usb-ffs/mtp/ep3";
-
 constexpr unsigned AIO_BUFS_MAX = 128;
 constexpr unsigned AIO_BUF_LEN = 16384;
 
@@ -73,7 +69,9 @@
     }
 }
 
-MtpFfsHandle::MtpFfsHandle() {}
+MtpFfsHandle::MtpFfsHandle(int controlFd) {
+    mControl.reset(controlFd);
+}
 
 MtpFfsHandle::~MtpFfsHandle() {}
 
@@ -83,27 +81,27 @@
     mBulkOut.reset();
 }
 
-bool MtpFfsHandle::openEndpoints() {
+bool MtpFfsHandle::openEndpoints(bool ptp) {
     if (mBulkIn < 0) {
-        mBulkIn.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP_IN, O_RDWR)));
+        mBulkIn.reset(TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP_IN : FFS_MTP_EP_IN, O_RDWR)));
         if (mBulkIn < 0) {
-            PLOG(ERROR) << FFS_MTP_EP_IN << ": cannot open bulk in ep";
+            PLOG(ERROR) << (ptp ? FFS_PTP_EP_IN : FFS_MTP_EP_IN) << ": cannot open bulk in ep";
             return false;
         }
     }
 
     if (mBulkOut < 0) {
-        mBulkOut.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP_OUT, O_RDWR)));
+        mBulkOut.reset(TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP_OUT : FFS_MTP_EP_OUT, O_RDWR)));
         if (mBulkOut < 0) {
-            PLOG(ERROR) << FFS_MTP_EP_OUT << ": cannot open bulk out ep";
+            PLOG(ERROR) << (ptp ? FFS_PTP_EP_OUT : FFS_MTP_EP_OUT) << ": cannot open bulk out ep";
             return false;
         }
     }
 
     if (mIntr < 0) {
-        mIntr.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP_INTR, O_RDWR)));
+        mIntr.reset(TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP_INTR : FFS_MTP_EP_INTR, O_RDWR)));
         if (mIntr < 0) {
-            PLOG(ERROR) << FFS_MTP_EP_INTR << ": cannot open intr ep";
+            PLOG(ERROR) << (ptp ? FFS_PTP_EP_INTR : FFS_MTP_EP_INTR) << ": cannot open intr ep";
             return false;
         }
     }
@@ -121,39 +119,8 @@
         PLOG(ERROR) << "Failed to fadvise";
 }
 
-bool MtpFfsHandle::initFunctionfs() {
-    if (mControl < 0) { // might have already done this before
-        mControl.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP0, O_RDWR)));
-        if (mControl < 0) {
-            PLOG(ERROR) << FFS_MTP_EP0 << ": cannot open control endpoint";
-            return false;
-        }
-        if (!writeDescriptors()) {
-            closeConfig();
-            return false;
-        }
-    }
-    return true;
-}
-
-bool MtpFfsHandle::writeDescriptors() {
-    ssize_t ret = TEMP_FAILURE_RETRY(::write(mControl,
-                &(mPtp ? ptp_desc_v2 : mtp_desc_v2), sizeof(desc_v2)));
-    if (ret < 0) {
-        PLOG(ERROR) << FFS_MTP_EP0 << "Switching to V1 descriptor format";
-        ret = TEMP_FAILURE_RETRY(::write(mControl,
-                    &(mPtp ? ptp_desc_v1 : mtp_desc_v1), sizeof(desc_v1)));
-        if (ret < 0) {
-            PLOG(ERROR) << FFS_MTP_EP0 << "Writing descriptors failed";
-            return false;
-        }
-    }
-    ret = TEMP_FAILURE_RETRY(::write(mControl, &mtp_strings, sizeof(mtp_strings)));
-    if (ret < 0) {
-        PLOG(ERROR) << FFS_MTP_EP0 << "Writing strings failed";
-        return false;
-    }
-    return true;
+bool MtpFfsHandle::writeDescriptors(bool ptp) {
+    return ::android::writeDescriptors(mControl, ptp);
 }
 
 void MtpFfsHandle::closeConfig() {
@@ -197,11 +164,9 @@
         switch (event->type) {
         case FUNCTIONFS_BIND:
         case FUNCTIONFS_ENABLE:
-        case FUNCTIONFS_RESUME:
             ret = 0;
             errno = 0;
             break;
-        case FUNCTIONFS_SUSPEND:
         case FUNCTIONFS_UNBIND:
         case FUNCTIONFS_DISABLE:
             errno = ESHUTDOWN;
@@ -211,6 +176,9 @@
             if (handleControlRequest(&event->u.setup) == -1)
                 ret = -1;
             break;
+        case FUNCTIONFS_SUSPEND:
+        case FUNCTIONFS_RESUME:
+            break;
         default:
             LOG(ERROR) << "Mtp Event " << event->type << " (unknown)";
         }
@@ -277,10 +245,8 @@
     return 0;
 }
 
-int MtpFfsHandle::start() {
-    mLock.lock();
-
-    if (!openEndpoints())
+int MtpFfsHandle::start(bool ptp) {
+    if (!openEndpoints(ptp))
         return -1;
 
     for (unsigned i = 0; i < NUM_IO_BUFS; i++) {
@@ -309,33 +275,10 @@
     return 0;
 }
 
-int MtpFfsHandle::configure(bool usePtp) {
-    // Wait till previous server invocation has closed
-    if (!mLock.try_lock_for(std::chrono::milliseconds(300))) {
-        LOG(ERROR) << "MtpServer was unable to get configure lock";
-        return -1;
-    }
-    int ret = 0;
-
-    // If ptp is changed, the configuration must be rewritten
-    if (mPtp != usePtp) {
-        closeEndpoints();
-        closeConfig();
-    }
-    mPtp = usePtp;
-
-    if (!initFunctionfs()) {
-        ret = -1;
-    }
-
-    mLock.unlock();
-    return ret;
-}
-
 void MtpFfsHandle::close() {
     io_destroy(mCtx);
     closeEndpoints();
-    mLock.unlock();
+    closeConfig();
 }
 
 int MtpFfsHandle::waitEvents(struct io_buffer *buf, int min_events, struct io_event *events,
diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h
index 2347000..24a8bd5 100644
--- a/media/mtp/MtpFfsHandle.h
+++ b/media/mtp/MtpFfsHandle.h
@@ -29,8 +29,6 @@
 
 namespace android {
 
-constexpr char FFS_MTP_EP0[] = "/dev/usb-ffs/mtp/ep0";
-
 constexpr int NUM_IO_BUFS = 2;
 
 struct io_buffer {
@@ -42,14 +40,10 @@
 };
 
 template <class T> class MtpFfsHandleTest;
-template <class T> class MtpFfsHandleTest_testControl_Test;
 
 class MtpFfsHandle : public IMtpHandle {
     template <class T> friend class MtpFfsHandleTest;
-    template <class T> friend class MtpFfsHandleTest_testControl_Test;
 protected:
-    bool initFunctionfs();
-    bool writeDescriptors();
     void closeConfig();
     void closeEndpoints();
     void advise(int fd);
@@ -58,15 +52,12 @@
     int handleEvent();
     void cancelTransaction();
     void doSendEvent(mtp_event me);
-    bool openEndpoints();
+    bool openEndpoints(bool ptp);
 
     static int getPacketSize(int ffs_fd);
 
-    bool mPtp;
     bool mCanceled;
 
-    std::timed_mutex mLock; // protects configure() vs main loop
-
     android::base::unique_fd mControl;
     // "in" from the host's perspective => sink for mtp server
     android::base::unique_fd mBulkIn;
@@ -99,12 +90,12 @@
     int sendFile(mtp_file_range mfr) override;
     int sendEvent(mtp_event me) override;
 
-    int start() override;
+    int start(bool ptp) override;
     void close() override;
 
-    int configure(bool ptp) override;
+    bool writeDescriptors(bool ptp);
 
-    MtpFfsHandle();
+    MtpFfsHandle(int controlFd);
     ~MtpFfsHandle();
 };
 
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index cfda0a6..e4ac8b0 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -33,6 +33,7 @@
 
 #include "MtpDebug.h"
 #include "IMtpDatabase.h"
+#include "MtpDescriptors.h"
 #include "MtpDevHandle.h"
 #include "MtpFfsCompatHandle.h"
 #include "MtpFfsHandle.h"
@@ -100,7 +101,7 @@
     MTP_EVENT_DEVICE_PROP_CHANGED,
 };
 
-MtpServer::MtpServer(IMtpDatabase* database, bool ptp,
+MtpServer::MtpServer(IMtpDatabase* database, int controlFd, bool ptp,
                     const MtpString& deviceInfoManufacturer,
                     const MtpString& deviceInfoModel,
                     const MtpString& deviceInfoDeviceVersion,
@@ -118,30 +119,18 @@
         mSendObjectFileSize(0),
         mSendObjectModifiedTime(0)
 {
+    bool ffs_ok = access(FFS_MTP_EP0, W_OK) == 0;
+    if (ffs_ok) {
+        bool aio_compat = android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false);
+        mHandle = aio_compat ? new MtpFfsCompatHandle(controlFd) : new MtpFfsHandle(controlFd);
+    } else {
+        mHandle = new MtpDevHandle();
+    }
 }
 
 MtpServer::~MtpServer() {
 }
 
-IMtpHandle* MtpServer::sHandle = nullptr;
-
-int MtpServer::configure(bool usePtp) {
-    bool ffs_ok = access(FFS_MTP_EP0, W_OK) == 0;
-    if (sHandle == nullptr) {
-        if (ffs_ok) {
-            bool aio_compat = android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false);
-            sHandle = aio_compat ? new MtpFfsCompatHandle() : new MtpFfsHandle();
-        } else {
-            sHandle = new MtpDevHandle();
-        }
-    }
-
-    int ret = sHandle->configure(usePtp);
-    if (ret) ALOGE("Failed to configure MTP driver!");
-    android::base::SetProperty("sys.usb.ffs.mtp.ready", "1");
-    return ret;
-}
-
 void MtpServer::addStorage(MtpStorage* storage) {
     Mutex::Autolock autoLock(mMutex);
 
@@ -175,19 +164,14 @@
 }
 
 void MtpServer::run() {
-    if (!sHandle) {
-        ALOGE("MtpServer was never configured!");
-        return;
-    }
-
-    if (sHandle->start()) {
+    if (mHandle->start(mPtp)) {
         ALOGE("Failed to start usb driver!");
-        sHandle->close();
+        mHandle->close();
         return;
     }
 
     while (1) {
-        int ret = mRequest.read(sHandle);
+        int ret = mRequest.read(mHandle);
         if (ret < 0) {
             ALOGE("request read returned %d, errno: %d", ret, errno);
             if (errno == ECANCELED) {
@@ -206,7 +190,7 @@
                     || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
                     || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
         if (dataIn) {
-            int ret = mData.read(sHandle);
+            int ret = mData.read(mHandle);
             if (ret < 0) {
                 ALOGE("data read returned %d, errno: %d", ret, errno);
                 if (errno == ECANCELED) {
@@ -225,7 +209,7 @@
                 mData.setOperationCode(operation);
                 mData.setTransactionID(transaction);
                 ALOGV("sending data:");
-                ret = mData.write(sHandle);
+                ret = mData.write(mHandle);
                 if (ret < 0) {
                     ALOGE("request write returned %d, errno: %d", ret, errno);
                     if (errno == ECANCELED) {
@@ -238,7 +222,7 @@
 
             mResponse.setTransactionID(transaction);
             ALOGV("sending response %04X", mResponse.getResponseCode());
-            ret = mResponse.write(sHandle);
+            ret = mResponse.write(mHandle);
             const int savedErrno = errno;
             if (ret < 0) {
                 ALOGE("request write returned %d, errno: %d", ret, errno);
@@ -262,7 +246,7 @@
     }
     mObjectEditList.clear();
 
-    sHandle->close();
+    mHandle->close();
 }
 
 void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
@@ -295,7 +279,7 @@
         mEvent.setEventCode(code);
         mEvent.setTransactionID(mRequest.getTransactionID());
         mEvent.setParameter(1, param1);
-        if (mEvent.write(sHandle))
+        if (mEvent.write(mHandle))
             ALOGE("Mtp send event failed: %s", strerror(errno));
     }
 }
@@ -806,7 +790,7 @@
     mfr.transaction_id = mRequest.getTransactionID();
 
     // then transfer the file
-    int ret = sHandle->sendFile(mfr);
+    int ret = mHandle->sendFile(mfr);
     if (ret < 0) {
         ALOGE("Mtp send file got error %s", strerror(errno));
         if (errno == ECANCELED) {
@@ -839,7 +823,7 @@
         // send data
         mData.setOperationCode(mRequest.getOperationCode());
         mData.setTransactionID(mRequest.getTransactionID());
-        mData.writeData(sHandle, thumb, thumbSize);
+        mData.writeData(mHandle, thumb, thumbSize);
         free(thumb);
         return MTP_RESPONSE_OK;
     } else {
@@ -894,7 +878,7 @@
     mResponse.setParameter(1, length);
 
     // transfer the file
-    int ret = sHandle->sendFile(mfr);
+    int ret = mHandle->sendFile(mfr);
     ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
     result = MTP_RESPONSE_OK;
     if (ret < 0) {
@@ -1176,7 +1160,7 @@
     }
 
     // read the header, and possibly some data
-    ret = mData.read(sHandle);
+    ret = mData.read(mHandle);
     if (ret < MTP_CONTAINER_HEADER_SIZE) {
         result = MTP_RESPONSE_GENERAL_ERROR;
         goto done;
@@ -1224,7 +1208,7 @@
         mfr.transaction_id = 0;
 
         // transfer the file
-        ret = sHandle->receiveFile(mfr, mfr.length == 0 &&
+        ret = mHandle->receiveFile(mfr, mfr.length == 0 &&
                 initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
         if ((ret < 0) && (errno == ECANCELED)) {
             isCanceled = true;
@@ -1353,7 +1337,7 @@
     ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
 
     // read the header, and possibly some data
-    int ret = mData.read(sHandle);
+    int ret = mData.read(mHandle);
     if (ret < MTP_CONTAINER_HEADER_SIZE)
         return MTP_RESPONSE_GENERAL_ERROR;
     int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
@@ -1376,7 +1360,7 @@
         mfr.transaction_id = 0;
 
         // transfer the file
-        ret = sHandle->receiveFile(mfr, mfr.length == 0 &&
+        ret = mHandle->receiveFile(mfr, mfr.length == 0 &&
                 initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
         if ((ret < 0) && (errno == ECANCELED)) {
             isCanceled = true;
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index af371eb..e633c52 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -65,7 +65,7 @@
 
     MtpStorageList      mStorages;
 
-    static IMtpHandle*  sHandle;
+    IMtpHandle*         mHandle;
 
     // handle for new object, set by SendObjectInfo and used by SendObject
     MtpObjectHandle     mSendObjectHandle;
@@ -98,7 +98,7 @@
     Vector<ObjectEdit*>  mObjectEditList;
 
 public:
-                        MtpServer(IMtpDatabase* database, bool ptp,
+                        MtpServer(IMtpDatabase* database, int controlFd, bool ptp,
                                     const MtpString& deviceInfoManufacturer,
                                     const MtpString& deviceInfoModel,
                                     const MtpString& deviceInfoDeviceVersion,
@@ -111,7 +111,6 @@
     void                addStorage(MtpStorage* storage);
     void                removeStorage(MtpStorage* storage);
 
-    static int          configure(bool usePtp);
     void                run();
 
     void                sendObjectAdded(MtpObjectHandle handle);
diff --git a/media/mtp/tests/MtpFfsHandle_test.cpp b/media/mtp/tests/MtpFfsHandle_test.cpp
index 9c916b7..2174893 100644
--- a/media/mtp/tests/MtpFfsHandle_test.cpp
+++ b/media/mtp/tests/MtpFfsHandle_test.cpp
@@ -64,7 +64,7 @@
 
     MtpFfsHandleTest() {
         int fd[2];
-        handle = std::make_unique<T>();
+        handle = std::make_unique<T>(-1);
 
         EXPECT_EQ(pipe(fd), 0);
         control.reset(fd[0]);
@@ -84,7 +84,7 @@
         intr.reset(fd[0]);
         handle->mIntr.reset(fd[1]);
 
-        EXPECT_EQ(handle->start(), 0);
+        EXPECT_EQ(handle->start(false), 0);
     }
 
     ~MtpFfsHandleTest() {
@@ -95,8 +95,8 @@
 typedef ::testing::Types<MtpFfsHandle, MtpFfsCompatHandle> mtpHandles;
 TYPED_TEST_CASE(MtpFfsHandleTest, mtpHandles);
 
-TYPED_TEST(MtpFfsHandleTest, testControl) {
-    EXPECT_TRUE(this->handle->writeDescriptors());
+TYPED_TEST(MtpFfsHandleTest, testMtpControl) {
+    EXPECT_TRUE(this->handle->writeDescriptors(false));
     struct desc_v2 desc;
     struct functionfs_strings strings;
     EXPECT_EQ(read(this->control, &desc, sizeof(desc)), (long)sizeof(desc));
@@ -105,6 +105,16 @@
     EXPECT_TRUE(std::memcmp(&strings, &mtp_strings, sizeof(strings)) == 0);
 }
 
+TYPED_TEST(MtpFfsHandleTest, testPtpControl) {
+    EXPECT_TRUE(this->handle->writeDescriptors(true));
+    struct desc_v2 desc;
+    struct functionfs_strings strings;
+    EXPECT_EQ(read(this->control, &desc, sizeof(desc)), (long)sizeof(desc));
+    EXPECT_EQ(read(this->control, &strings, sizeof(strings)), (long)sizeof(strings));
+    EXPECT_TRUE(std::memcmp(&desc, &ptp_desc_v2, sizeof(desc)) == 0);
+    EXPECT_TRUE(std::memcmp(&strings, &mtp_strings, sizeof(strings)) == 0);
+}
+
 TYPED_TEST(MtpFfsHandleTest, testRead) {
     EXPECT_EQ(write(this->bulk_out, dummyDataStr.c_str(), TEST_PACKET_SIZE), TEST_PACKET_SIZE);
     char buf[TEST_PACKET_SIZE + 1];
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
index 721e0a2..249365a 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
@@ -16,20 +16,20 @@
 
 package com.android.media;
 
-import static android.media.MediaSession2.COMMAND_CODE_PLAYBACK_SET_VOLUME;
-import static android.media.MediaSession2.COMMAND_CODE_PLAYLIST_ADD_ITEM;
-import static android.media.MediaSession2.COMMAND_CODE_PLAYLIST_REMOVE_ITEM;
-import static android.media.MediaSession2.COMMAND_CODE_PLAYLIST_REPLACE_ITEM;
-import static android.media.MediaSession2.COMMAND_CODE_PLAYLIST_SET_LIST;
-import static android.media.MediaSession2.COMMAND_CODE_PLAYLIST_SET_LIST_METADATA;
-import static android.media.MediaSession2.COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE;
-import static android.media.MediaSession2.COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE;
-import static android.media.MediaSession2.COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID;
-import static android.media.MediaSession2.COMMAND_CODE_SESSION_PLAY_FROM_SEARCH;
-import static android.media.MediaSession2.COMMAND_CODE_SESSION_PLAY_FROM_URI;
-import static android.media.MediaSession2.COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID;
-import static android.media.MediaSession2.COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH;
-import static android.media.MediaSession2.COMMAND_CODE_SESSION_PREPARE_FROM_URI;
+import static android.media.SessionCommand2.COMMAND_CODE_SET_VOLUME;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_ADD_ITEM;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_REMOVE_ITEM;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_REPLACE_ITEM;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SET_LIST;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SET_LIST_METADATA;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE;
+import static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_SEARCH;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_URI;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH;
+import static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_URI;
 
 import android.app.PendingIntent;
 import android.content.ComponentName;
@@ -44,10 +44,9 @@
 import android.media.MediaMetadata2;
 import android.media.MediaPlaylistAgent.RepeatMode;
 import android.media.MediaPlaylistAgent.ShuffleMode;
-import android.media.MediaSession2;
-import android.media.MediaSession2.Command;
+import android.media.SessionCommand2;
 import android.media.MediaSession2.CommandButton;
-import android.media.MediaSession2.CommandGroup;
+import android.media.SessionCommandGroup2;
 import android.media.MediaSessionService2;
 import android.media.Rating2;
 import android.media.SessionToken2;
@@ -108,7 +107,7 @@
     @GuardedBy("mLock")
     private PendingIntent mSessionActivity;
     @GuardedBy("mLock")
-    private CommandGroup mAllowedCommands;
+    private SessionCommandGroup2 mAllowedCommands;
 
     // Assignment should be used with the lock hold, but should be used without a lock to prevent
     // potential deadlock.
@@ -297,7 +296,7 @@
     }
 
     // Returns session binder if the controller can send the command.
-    IMediaSession2 getSessionBinderIfAble(Command command) {
+    IMediaSession2 getSessionBinderIfAble(SessionCommand2 command) {
         synchronized (mLock) {
             if (!mAllowedCommands.hasCommand(command)) {
                 Log.w(TAG, "Controller isn't allowed to call command, command=" + command);
@@ -326,17 +325,17 @@
 
     @Override
     public void play_impl() {
-        sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_PLAY);
+        sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY);
     }
 
     @Override
     public void pause_impl() {
-        sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_PAUSE);
+        sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE);
     }
 
     @Override
     public void stop_impl() {
-        sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_STOP);
+        sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_STOP);
     }
 
     @Override
@@ -409,7 +408,7 @@
     @Override
     public void setVolumeTo_impl(int value, int flags) {
         // TODO(hdmoon): sanity check
-        final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYBACK_SET_VOLUME);
+        final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SET_VOLUME);
         if (binder != null) {
             try {
                 binder.setVolumeTo(mControllerStub, value, flags);
@@ -424,7 +423,7 @@
     @Override
     public void adjustVolume_impl(int direction, int flags) {
         // TODO(hdmoon): sanity check
-        final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYBACK_SET_VOLUME);
+        final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SET_VOLUME);
         if (binder != null) {
             try {
                 binder.adjustVolume(mControllerStub, direction, flags);
@@ -563,7 +562,7 @@
     }
 
     @Override
-    public void sendCustomCommand_impl(Command command, Bundle args, ResultReceiver cb) {
+    public void sendCustomCommand_impl(SessionCommand2 command, Bundle args, ResultReceiver cb) {
         if (command == null) {
             throw new IllegalArgumentException("command shouldn't be null");
         }
@@ -633,17 +632,19 @@
 
     @Override
     public void prepare_impl() {
-        sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_PREPARE);
+        sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_PREPARE);
     }
 
     @Override
     public void fastForward_impl() {
-        sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_FAST_FORWARD);
+        // TODO(jaewan): Implement this. Note that fast forward isn't a transport command anymore
+        //sendTransportControlCommand(MediaSession2.COMMAND_CODE_SESSION_FAST_FORWARD);
     }
 
     @Override
     public void rewind_impl() {
-        sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_REWIND);
+        // TODO(jaewan): Implement this. Note that rewind isn't a transport command anymore
+        //sendTransportControlCommand(MediaSession2.COMMAND_CODE_SESSION_REWIND);
     }
 
     @Override
@@ -653,7 +654,7 @@
         }
         Bundle args = new Bundle();
         args.putLong(MediaSession2Stub.ARGUMENT_KEY_POSITION, pos);
-        sendTransportControlCommand(MediaSession2.COMMAND_CODE_PLAYBACK_SEEK_TO, args);
+        sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_SEEK_TO, args);
     }
 
     @Override
@@ -807,6 +808,7 @@
         });
     }
 
+    // TODO(jaewan): Rename to seek completed
     void pushPositionChanges(final long eventTimeMs, final long positionMs) {
         synchronized (mLock) {
             mPositionEventTimeMs = eventTimeMs;
@@ -816,7 +818,7 @@
             if (!mInstance.isConnected()) {
                 return;
             }
-            mCallback.onPositionChanged(mInstance, eventTimeMs, positionMs);
+            mCallback.onSeekCompleted(mInstance, positionMs);
         });
     }
 
@@ -917,7 +919,7 @@
 
     // Should be used without a lock to prevent potential deadlock.
     void onConnectedNotLocked(IMediaSession2 sessionBinder,
-            final CommandGroup allowedCommands,
+            final SessionCommandGroup2 allowedCommands,
             final int playerState,
             final long positionEventTimeMs,
             final long positionMs,
@@ -989,7 +991,7 @@
         }
     }
 
-    void onCustomCommand(final Command command, final Bundle args,
+    void onCustomCommand(final SessionCommand2 command, final Bundle args,
             final ResultReceiver receiver) {
         if (DEBUG) {
             Log.d(TAG, "onCustomCommand cmd=" + command);
@@ -1000,7 +1002,7 @@
         });
     }
 
-    void onAllowedCommandsChanged(final CommandGroup commands) {
+    void onAllowedCommandsChanged(final SessionCommandGroup2 commands) {
         mCallbackExecutor.execute(() -> {
             mCallback.onAllowedCommandsChanged(mInstance, commands);
         });
@@ -1062,7 +1064,6 @@
         private static final String KEY_AUDIO_ATTRIBUTES =
                 "android.media.playbackinfo_impl.audio_attrs";
 
-        private final Context mContext;
         private final PlaybackInfo mInstance;
 
         private final int mPlaybackType;
@@ -1071,9 +1072,8 @@
         private final int mCurrentVolume;
         private final AudioAttributes mAudioAttrs;
 
-        private PlaybackInfoImpl(Context context, int playbackType, AudioAttributes attrs,
-                int controlType, int max, int current) {
-            mContext = context;
+        private PlaybackInfoImpl(int playbackType, AudioAttributes attrs, int controlType,
+                int max, int current) {
             mPlaybackType = playbackType;
             mAudioAttrs = attrs;
             mControlType = controlType;
@@ -1107,11 +1107,11 @@
             return mCurrentVolume;
         }
 
-        public PlaybackInfo getInstance() {
+        PlaybackInfo getInstance() {
             return mInstance;
         }
 
-        public Bundle toBundle() {
+        Bundle toBundle() {
             Bundle bundle = new Bundle();
             bundle.putInt(KEY_PLAYBACK_TYPE, mPlaybackType);
             bundle.putInt(KEY_CONTROL_TYPE, mControlType);
@@ -1121,13 +1121,13 @@
             return bundle;
         }
 
-        public static PlaybackInfo createPlaybackInfo(Context context, int playbackType,
-                AudioAttributes attrs, int controlType, int max, int current) {
-            return new PlaybackInfoImpl(context, playbackType, attrs, controlType, max, current)
+        static PlaybackInfo createPlaybackInfo(int playbackType, AudioAttributes attrs,
+                int controlType, int max, int current) {
+            return new PlaybackInfoImpl(playbackType, attrs, controlType, max, current)
                     .getInstance();
         }
 
-        public static PlaybackInfo fromBundle(Context context, Bundle bundle) {
+        static PlaybackInfo fromBundle(Bundle bundle) {
             if (bundle == null) {
                 return null;
             }
@@ -1137,8 +1137,7 @@
             final int currentVolume = bundle.getInt(KEY_CURRENT_VOLUME);
             final AudioAttributes attrs = bundle.getParcelable(KEY_AUDIO_ATTRIBUTES);
 
-            return createPlaybackInfo(
-                    context, volumeType, attrs, volumeControl, maxVolume, currentVolume);
+            return createPlaybackInfo(volumeType, attrs, volumeControl, maxVolume, currentVolume);
         }
     }
 }
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Stub.java b/packages/MediaComponents/src/com/android/media/MediaController2Stub.java
index 721c963..2cfc5df 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Stub.java
@@ -21,9 +21,9 @@
 import android.media.MediaController2;
 import android.media.MediaItem2;
 import android.media.MediaMetadata2;
-import android.media.MediaSession2.Command;
+import android.media.SessionCommand2;
 import android.media.MediaSession2.CommandButton;
-import android.media.MediaSession2.CommandGroup;
+import android.media.SessionCommandGroup2;
 import android.os.Bundle;
 import android.os.ResultReceiver;
 import android.text.TextUtils;
@@ -141,15 +141,14 @@
         }
         List<MediaItem2> playlist = new ArrayList<>();
         for (Bundle bundle : playlistBundle) {
-            MediaItem2 item = MediaItem2.fromBundle(controller.getContext(), bundle);
+            MediaItem2 item = MediaItem2.fromBundle(bundle);
             if (item == null) {
                 Log.w(TAG, "onPlaylistChanged(): Ignoring null item in playlist");
             } else {
                 playlist.add(item);
             }
         }
-        MediaMetadata2 metadata =
-                MediaMetadata2.fromBundle(controller.getContext(), metadataBundle);
+        MediaMetadata2 metadata = MediaMetadata2.fromBundle(metadataBundle);
         controller.pushPlaylistChanges(playlist, metadata);
     }
 
@@ -162,8 +161,7 @@
             Log.w(TAG, "Don't fail silently here. Highly likely a bug");
             return;
         }
-        MediaMetadata2 metadata =
-                MediaMetadata2.fromBundle(controller.getContext(), metadataBundle);
+        MediaMetadata2 metadata = MediaMetadata2.fromBundle(metadataBundle);
         controller.pushPlaylistMetadataChanges(metadata);
     }
 
@@ -191,14 +189,12 @@
             Log.w(TAG, "Don't fail silently here. Highly likely a bug");
             return;
         }
-        MediaController2.PlaybackInfo info =
-                PlaybackInfoImpl.fromBundle(controller.getContext(), playbackInfo);
+        MediaController2.PlaybackInfo info = PlaybackInfoImpl.fromBundle(playbackInfo);
         if (info == null) {
             Log.w(TAG, "onPlaybackInfoChanged(): Ignoring null playbackInfo");
             return;
         }
-        controller.pushPlaybackInfoChanges(
-                PlaybackInfoImpl.fromBundle(controller.getContext(), playbackInfo));
+        controller.pushPlaybackInfoChanges(info);
     }
 
     @Override
@@ -242,16 +238,16 @@
         if (itemBundleList != null) {
             itemList = new ArrayList<>();
             for (int i = 0; i < itemBundleList.size(); i++) {
-                MediaItem2 item = MediaItem2.fromBundle(context, itemBundleList.get(i));
+                MediaItem2 item = MediaItem2.fromBundle(itemBundleList.get(i));
                 if (item != null) {
                     itemList.add(item);
                 }
             }
         }
         controller.onConnectedNotLocked(sessionBinder,
-                CommandGroup.fromBundle(context, commandGroup),
+                SessionCommandGroup2.fromBundle(commandGroup),
                 playerState, positionEventTimeMs, positionMs, playbackSpeed, bufferedPositionMs,
-                PlaybackInfoImpl.fromBundle(context, playbackInfo), repeatMode, shuffleMode,
+                PlaybackInfoImpl.fromBundle(playbackInfo), repeatMode, shuffleMode,
                 itemList, sessionActivity);
     }
 
@@ -286,8 +282,7 @@
         }
         List<CommandButton> layout = new ArrayList<>();
         for (int i = 0; i < commandButtonlist.size(); i++) {
-            CommandButton button = CommandButtonImpl.fromBundle(
-                    controller.getContext(), commandButtonlist.get(i));
+            CommandButton button = CommandButtonImpl.fromBundle(commandButtonlist.get(i));
             if (button != null) {
                 layout.add(button);
             }
@@ -308,7 +303,7 @@
             // TODO(jaewan): Revisit here. Could be a bug
             return;
         }
-        CommandGroup commands = CommandGroup.fromBundle(controller.getContext(), commandsBundle);
+        SessionCommandGroup2 commands = SessionCommandGroup2.fromBundle(commandsBundle);
         if (commands == null) {
             Log.w(TAG, "onAllowedCommandsChanged(): Ignoring null commands");
             return;
@@ -325,7 +320,7 @@
             Log.w(TAG, "Don't fail silently here. Highly likely a bug");
             return;
         }
-        Command command = Command.fromBundle(controller.getContext(), commandBundle);
+        SessionCommand2 command = SessionCommand2.fromBundle(commandBundle);
         if (command == null) {
             Log.w(TAG, "onCustomCommand(): Ignoring null command");
             return;
@@ -371,8 +366,7 @@
             // TODO(jaewan): Revisit here. Could be a bug
             return;
         }
-        browser.onGetItemDone(mediaId,
-                MediaItem2Impl.fromBundle(browser.getContext(), itemBundle));
+        browser.onGetItemDone(mediaId, MediaItem2.fromBundle(itemBundle));
     }
 
     @Override
@@ -398,7 +392,7 @@
         if (itemBundleList != null) {
             result = new ArrayList<>();
             for (Bundle bundle : itemBundleList) {
-                result.add(MediaItem2.fromBundle(browser.getContext(), bundle));
+                result.add(MediaItem2.fromBundle(bundle));
             }
         }
         browser.onGetChildrenDone(parentId, page, pageSize, result, extras);
@@ -448,7 +442,7 @@
         if (itemBundleList != null) {
             result = new ArrayList<>();
             for (Bundle bundle : itemBundleList) {
-                result.add(MediaItem2.fromBundle(browser.getContext(), bundle));
+                result.add(MediaItem2.fromBundle(bundle));
             }
         }
         browser.onGetSearchResultDone(query, page, pageSize, result, extras);
diff --git a/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java b/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
index c95b43f..910a0f1 100644
--- a/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
@@ -21,7 +21,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.Context;
 import android.media.DataSourceDesc;
 import android.media.MediaItem2;
 import android.media.MediaItem2.Builder;
@@ -39,7 +38,6 @@
     private static final String KEY_METADATA = "android.media.mediaitem2.metadata";
     private static final String KEY_UUID = "android.media.mediaitem2.uuid";
 
-    private final Context mContext;
     private final MediaItem2 mInstance;
     private final String mId;
     private final int mFlags;
@@ -48,14 +46,13 @@
     private DataSourceDesc mDataSourceDesc;
 
     // From the public API
-    public MediaItem2Impl(@NonNull Context context, @NonNull String mediaId,
-            @Nullable DataSourceDesc dsd, @Nullable MediaMetadata2 metadata, @Flags int flags) {
-        this(context, mediaId, dsd, metadata, flags, null);
+    public MediaItem2Impl(@NonNull String mediaId, @Nullable DataSourceDesc dsd,
+            @Nullable MediaMetadata2 metadata, @Flags int flags) {
+        this(mediaId, dsd, metadata, flags, null);
     }
 
-    private MediaItem2Impl(@NonNull Context context, @NonNull String mediaId,
-            @Nullable DataSourceDesc dsd, @Nullable MediaMetadata2 metadata, @Flags int flags,
-            @Nullable UUID uuid) {
+    private MediaItem2Impl(@NonNull String mediaId, @Nullable DataSourceDesc dsd,
+            @Nullable MediaMetadata2 metadata, @Flags int flags, @Nullable UUID uuid) {
         if (mediaId == null) {
             throw new IllegalArgumentException("mediaId shouldn't be null");
         }
@@ -63,7 +60,6 @@
             throw new IllegalArgumentException("metadata's id should be matched with the mediaid");
         }
 
-        mContext = context;
         mId = mediaId;
         mDataSourceDesc = dsd;
         mMetadata = metadata;
@@ -101,16 +97,15 @@
     /**
      * Create a MediaItem2 from the {@link Bundle}.
      *
-     * @param context A context.
      * @param bundle The bundle which was published by {@link MediaItem2#toBundle()}.
      * @return The newly created MediaItem2
      */
-    public static MediaItem2 fromBundle(@NonNull Context context, @NonNull Bundle bundle) {
+    public static MediaItem2 fromBundle_impl(@NonNull Bundle bundle) {
         if (bundle == null) {
             return null;
         }
         final String uuidString = bundle.getString(KEY_UUID);
-        return fromBundle(context, bundle, UUID.fromString(uuidString));
+        return fromBundle(bundle, UUID.fromString(uuidString));
     }
 
     /**
@@ -118,22 +113,19 @@
      * If {@link UUID}
      * can be null for creating new.
      *
-     * @param context A context.
      * @param bundle The bundle which was published by {@link MediaItem2#toBundle()}.
      * @param uuid A {@link UUID} to override. Can be {@link null} for override.
      * @return The newly created MediaItem2
      */
-    static MediaItem2 fromBundle(@NonNull Context context, @NonNull Bundle bundle,
-            @Nullable UUID uuid) {
+    static MediaItem2 fromBundle(@NonNull Bundle bundle, @Nullable UUID uuid) {
         if (bundle == null) {
             return null;
         }
         final String id = bundle.getString(KEY_ID);
         final Bundle metadataBundle = bundle.getBundle(KEY_METADATA);
-        final MediaMetadata2 metadata = metadataBundle != null
-                ? MediaMetadata2.fromBundle(context, metadataBundle) : null;
+        final MediaMetadata2 metadata = MediaMetadata2.fromBundle(metadataBundle);
         final int flags = bundle.getInt(KEY_FLAGS);
-        return new MediaItem2Impl(context, id, null, metadata, flags, uuid).getInstance();
+        return new MediaItem2Impl(id, null, metadata, flags, uuid).getInstance();
     }
 
     private MediaItem2 getInstance() {
@@ -188,15 +180,13 @@
     }
 
     public static class BuilderImpl implements MediaItem2Provider.BuilderProvider {
-        private Context mContext;
         private Builder mInstance;
         private @Flags int mFlags;
         private String mMediaId;
         private MediaMetadata2 mMetadata;
         private DataSourceDesc mDataSourceDesc;
 
-        public BuilderImpl(Context context, Builder instance, int flags) {
-            mContext = context;
+        public BuilderImpl(Builder instance, int flags) {
             mInstance = instance;
             mFlags = flags;
         }
@@ -227,8 +217,7 @@
                 //  TODO(jaewan): Double check if its sufficient (e.g. Use UUID instead?)
                 id = (mMediaId != null) ? mMediaId : toString();
             }
-            return new MediaItem2Impl(mContext, id, mDataSourceDesc, mMetadata, mFlags)
-                    .getInstance();
+            return new MediaItem2Impl(id, mDataSourceDesc, mMetadata, mFlags).getInstance();
         }
     }
 }
diff --git a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
index b3512cc..cf34cd4 100644
--- a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
@@ -151,8 +151,7 @@
         private final String mRootId;
         private final Bundle mExtras;
 
-        public LibraryRootImpl(Context context, LibraryRoot instance, String rootId,
-                Bundle extras) {
+        public LibraryRootImpl(LibraryRoot instance, String rootId, Bundle extras) {
             if (rootId == null) {
                 throw new IllegalArgumentException("rootId shouldn't be null.");
             }
diff --git a/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java b/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java
index 5fd5812..cf1c532 100644
--- a/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java
@@ -19,7 +19,6 @@
 import static android.media.MediaMetadata2.*;
 
 import android.annotation.Nullable;
-import android.content.Context;
 import android.graphics.Bitmap;
 import android.media.MediaMetadata2;
 import android.media.MediaMetadata2.BitmapKey;
@@ -105,12 +104,10 @@
             METADATA_KEY_ALBUM_ART_URI
     };
 
-    private final Context mContext;
     private final MediaMetadata2 mInstance;
     private final Bundle mBundle;
 
-    public MediaMetadata2Impl(Context context, Bundle bundle) {
-        mContext = context;
+    public MediaMetadata2Impl(Bundle bundle) {
         mInstance = new MediaMetadata2(this);
         mBundle = bundle;
     }
@@ -168,7 +165,7 @@
         // TODO(jaewan): Add backward compatibility
         Rating2 rating = null;
         try {
-            rating = Rating2.fromBundle(mContext, mBundle.getBundle(key));
+            rating = Rating2.fromBundle(mBundle.getBundle(key));
         } catch (Exception e) {
             // ignore, value was not a rating
             Log.w(TAG, "Failed to retrieve a key as Rating.", e);
@@ -225,33 +222,28 @@
         return mBundle;
     }
 
-    public static MediaMetadata2 fromBundle(Context context, Bundle bundle) {
-        return (bundle == null) ? null : new MediaMetadata2Impl(context, bundle).getInstance();
+    public static MediaMetadata2 fromBundle_impl(Bundle bundle) {
+        return (bundle == null) ? null : new MediaMetadata2Impl(bundle).getInstance();
     }
 
     public static final class BuilderImpl implements MediaMetadata2Provider.BuilderProvider {
-        private final Context mContext;
         private final MediaMetadata2.Builder mInstance;
         private final Bundle mBundle;
 
-        public BuilderImpl(Context context, MediaMetadata2.Builder instance) {
-            mContext = context;
+        public BuilderImpl(MediaMetadata2.Builder instance) {
             mInstance = instance;
             mBundle = new Bundle();
         }
 
-        public BuilderImpl(Context context, MediaMetadata2.Builder instance,
-                MediaMetadata2 source) {
+        public BuilderImpl(MediaMetadata2.Builder instance, MediaMetadata2 source) {
             if (source == null) {
                 throw new IllegalArgumentException("source shouldn't be null");
             }
-            mContext = context;
             mInstance = instance;
             mBundle = new Bundle(source.toBundle());
         }
 
-        public BuilderImpl(Context context, int maxBitmapSize) {
-            mContext = context;
+        public BuilderImpl(int maxBitmapSize) {
             mInstance = new MediaMetadata2.Builder(this);
             mBundle = new Bundle();
 
@@ -364,7 +356,7 @@
 
         @Override
         public MediaMetadata2 build_impl() {
-            return new MediaMetadata2Impl(mContext, mBundle).getInstance();
+            return new MediaMetadata2Impl(mBundle).getInstance();
         }
 
         private Bitmap scaleBitmap(Bitmap bmp, int maxSize) {
diff --git a/packages/MediaComponents/src/com/android/media/MediaPlaylistAgentImpl.java b/packages/MediaComponents/src/com/android/media/MediaPlaylistAgentImpl.java
index ab6b167..dfd4e1a 100644
--- a/packages/MediaComponents/src/com/android/media/MediaPlaylistAgentImpl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaPlaylistAgentImpl.java
@@ -19,7 +19,6 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.Context;
 import android.media.DataSourceDesc;
 import android.media.MediaItem2;
 import android.media.MediaMetadata2;
@@ -37,15 +36,13 @@
 public class MediaPlaylistAgentImpl implements MediaPlaylistAgentProvider {
     private static final String TAG = "MediaPlaylistAgent";
 
-    private final Context mContext;
     private final MediaPlaylistAgent mInstance;
 
     private final Object mLock = new Object();
     @GuardedBy("mLock")
     private final ArrayMap<PlaylistEventCallback, Executor> mCallbacks = new ArrayMap<>();
 
-    public MediaPlaylistAgentImpl(Context context, MediaPlaylistAgent instance) {
-        mContext = context;
+    public MediaPlaylistAgentImpl(MediaPlaylistAgent instance) {
         mInstance = instance;
     }
 
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
index 2d04765..e099d95 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
@@ -16,7 +16,7 @@
 
 package com.android.media;
 
-import static android.media.MediaSession2.COMMAND_CODE_CUSTOM;
+import static android.media.SessionCommand2.COMMAND_CODE_CUSTOM;
 import static android.media.SessionToken2.TYPE_LIBRARY_SERVICE;
 import static android.media.SessionToken2.TYPE_SESSION;
 import static android.media.SessionToken2.TYPE_SESSION_SERVICE;
@@ -44,9 +44,9 @@
 import android.media.MediaPlaylistAgent.PlaylistEventCallback;
 import android.media.MediaSession2;
 import android.media.MediaSession2.Builder;
-import android.media.MediaSession2.Command;
+import android.media.SessionCommand2;
 import android.media.MediaSession2.CommandButton;
-import android.media.MediaSession2.CommandGroup;
+import android.media.SessionCommandGroup2;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSession2.OnDataSourceMissingHelper;
 import android.media.MediaSession2.SessionCallback;
@@ -158,13 +158,13 @@
             throw new IllegalArgumentException("Ambiguous session type. Multiple"
                     + " session services define the same id=" + id);
         } else if (libraryService != null) {
-            mSessionToken = new SessionToken2Impl(context, Process.myUid(), TYPE_LIBRARY_SERVICE,
+            mSessionToken = new SessionToken2Impl(Process.myUid(), TYPE_LIBRARY_SERVICE,
                     mContext.getPackageName(), libraryService, id, mSessionStub).getInstance();
         } else if (sessionService != null) {
-            mSessionToken = new SessionToken2Impl(context, Process.myUid(), TYPE_SESSION_SERVICE,
+            mSessionToken = new SessionToken2Impl(Process.myUid(), TYPE_SESSION_SERVICE,
                     mContext.getPackageName(), sessionService, id, mSessionStub).getInstance();
         } else {
-            mSessionToken = new SessionToken2Impl(context, Process.myUid(), TYPE_SESSION,
+            mSessionToken = new SessionToken2Impl(Process.myUid(), TYPE_SESSION,
                     mContext.getPackageName(), null, id, mSessionStub).getInstance();
         }
 
@@ -232,7 +232,7 @@
             oldAgent = mPlaylistAgent;
             mPlayer = player;
             if (agent == null) {
-                mSessionPlaylistAgent = new SessionPlaylistAgent(mContext, this, mPlayer);
+                mSessionPlaylistAgent = new SessionPlaylistAgent(this, mPlayer);
                 if (mDsmHelper != null) {
                     mSessionPlaylistAgent.setOnDataSourceMissingHelper(mDsmHelper);
                 }
@@ -280,7 +280,6 @@
                 }
             }
             info = MediaController2Impl.PlaybackInfoImpl.createPlaybackInfo(
-                    mContext,
                     PlaybackInfo.PLAYBACK_TYPE_LOCAL,
                     attrs,
                     mAudioManager.isVolumeFixed()
@@ -290,7 +289,6 @@
                     mAudioManager.getStreamVolume(stream));
         } else {
             info = MediaController2Impl.PlaybackInfoImpl.createPlaybackInfo(
-                    mContext,
                     PlaybackInfo.PLAYBACK_TYPE_REMOTE /* ControlType */,
                     attrs,
                     volumeProvider.getControlType(),
@@ -446,7 +444,7 @@
 
     @Override
     public void setAllowedCommands_impl(@NonNull ControllerInfo controller,
-            @NonNull CommandGroup commands) {
+            @NonNull SessionCommandGroup2 commands) {
         if (controller == null) {
             throw new IllegalArgumentException("controller shouldn't be null");
         }
@@ -457,8 +455,8 @@
     }
 
     @Override
-    public void sendCustomCommand_impl(@NonNull ControllerInfo controller, @NonNull Command command,
-            Bundle args, ResultReceiver receiver) {
+    public void sendCustomCommand_impl(@NonNull ControllerInfo controller,
+            @NonNull SessionCommand2 command, Bundle args, ResultReceiver receiver) {
         if (controller == null) {
             throw new IllegalArgumentException("controller shouldn't be null");
         }
@@ -469,7 +467,7 @@
     }
 
     @Override
-    public void sendCustomCommand_impl(@NonNull Command command, Bundle args) {
+    public void sendCustomCommand_impl(@NonNull SessionCommand2 command, Bundle args) {
         if (command == null) {
             throw new IllegalArgumentException("command shouldn't be null");
         }
@@ -627,28 +625,6 @@
     }
 
     @Override
-    public void fastForward_impl() {
-        ensureCallingThread();
-        final MediaPlayerBase player = mPlayer;
-        if (player != null) {
-            player.fastForward();
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void rewind_impl() {
-        ensureCallingThread();
-        final MediaPlayerBase player = mPlayer;
-        if (player != null) {
-            player.rewind();
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
     public void seekTo_impl(long pos) {
         ensureCallingThread();
         final MediaPlayerBase player = mPlayer;
@@ -1004,20 +980,21 @@
         private static final String KEY_COMMAND_EXTRAS
                 = "android.media.media_session2.command.extras";
 
-        private final Command mInstance;
+        private final SessionCommand2 mInstance;
         private final int mCommandCode;
         // Nonnull if it's custom command
         private final String mCustomCommand;
         private final Bundle mExtras;
 
-        public CommandImpl(Command instance, int commandCode) {
+        public CommandImpl(SessionCommand2 instance, int commandCode) {
             mInstance = instance;
             mCommandCode = commandCode;
             mCustomCommand = null;
             mExtras = null;
         }
 
-        public CommandImpl(Command instance, @NonNull String action, @Nullable Bundle extras) {
+        public CommandImpl(SessionCommand2 instance, @NonNull String action,
+                @Nullable Bundle extras) {
             if (action == null) {
                 throw new IllegalArgumentException("action shouldn't be null");
             }
@@ -1057,19 +1034,19 @@
         /**
          * @return a new Command instance from the Bundle
          */
-        public static Command fromBundle_impl(Context context, @NonNull Bundle command) {
+        public static SessionCommand2 fromBundle_impl(@NonNull Bundle command) {
             if (command == null) {
                 throw new IllegalArgumentException("command shouldn't be null");
             }
             int code = command.getInt(KEY_COMMAND_CODE);
             if (code != COMMAND_CODE_CUSTOM) {
-                return new Command(context, code);
+                return new SessionCommand2(code);
             } else {
                 String customCommand = command.getString(KEY_COMMAND_CUSTOM_COMMAND);
                 if (customCommand == null) {
                     return null;
                 }
-                return new Command(context, customCommand, command.getBundle(KEY_COMMAND_EXTRAS));
+                return new SessionCommand2(customCommand, command.getBundle(KEY_COMMAND_EXTRAS));
             }
         }
 
@@ -1093,7 +1070,7 @@
     }
 
     /**
-     * Represent set of {@link Command}.
+     * Represent set of {@link SessionCommand2}.
      */
     public static class CommandGroupImpl implements CommandGroupProvider {
         private static final String KEY_COMMANDS =
@@ -1108,25 +1085,22 @@
         // Prefix for command codes that will be sent directly to the MediaPlaylistAgent
         private static final String PREFIX_COMMAND_CODE_PLAYLIST = "COMMAND_CODE_PLAYLIST_";
 
-        private Set<Command> mCommands = new HashSet<>();
-        private final Context mContext;
-        private final CommandGroup mInstance;
+        private Set<SessionCommand2> mCommands = new HashSet<>();
+        private final SessionCommandGroup2 mInstance;
 
-        public CommandGroupImpl(Context context, CommandGroup instance, Object other) {
-            mContext = context;
+        public CommandGroupImpl(SessionCommandGroup2 instance, Object other) {
             mInstance = instance;
             if (other != null && other instanceof CommandGroupImpl) {
                 mCommands.addAll(((CommandGroupImpl) other).mCommands);
             }
         }
 
-        public CommandGroupImpl(Context context) {
-            mContext = context;
-            mInstance = new CommandGroup(this);
+        public CommandGroupImpl() {
+            mInstance = new SessionCommandGroup2(this);
         }
 
         @Override
-        public void addCommand_impl(@NonNull Command command) {
+        public void addCommand_impl(@NonNull SessionCommand2 command) {
             if (command == null) {
                 throw new IllegalArgumentException("command shouldn't be null");
             }
@@ -1138,11 +1112,11 @@
             addCommandsWithPrefix(PREFIX_COMMAND_CODE);
         }
 
-        public void addAllPlaybackCommands() {
+        void addAllPlaybackCommands() {
             addCommandsWithPrefix(PREFIX_COMMAND_CODE_PLAYBACK);
         }
 
-        public void addAllPlaylistCommands() {
+        void addAllPlaylistCommands() {
             addCommandsWithPrefix(PREFIX_COMMAND_CODE_PLAYLIST);
         }
 
@@ -1153,7 +1127,7 @@
                 for (int i = 0; i < fields.length; i++) {
                     if (fields[i].getName().startsWith(prefix)) {
                         try {
-                            mCommands.add(new Command(mContext, fields[i].getInt(null)));
+                            mCommands.add(new SessionCommand2(fields[i].getInt(null)));
                         } catch (IllegalAccessException e) {
                             Log.w(TAG, "Unexpected " + fields[i] + " in MediaSession2");
                         }
@@ -1163,7 +1137,7 @@
         }
 
         @Override
-        public void removeCommand_impl(@NonNull Command command) {
+        public void removeCommand_impl(@NonNull SessionCommand2 command) {
             if (command == null) {
                 throw new IllegalArgumentException("command shouldn't be null");
             }
@@ -1171,7 +1145,7 @@
         }
 
         @Override
-        public boolean hasCommand_impl(@NonNull Command command) {
+        public boolean hasCommand_impl(@NonNull SessionCommand2 command) {
             if (command == null) {
                 throw new IllegalArgumentException("command shouldn't be null");
             }
@@ -1183,7 +1157,7 @@
             if (code == COMMAND_CODE_CUSTOM) {
                 throw new IllegalArgumentException("Use hasCommand(Command) for custom command");
             }
-            for (Command command : mCommands) {
+            for (SessionCommand2 command : mCommands) {
                 if (command.getCommandCode() == code) {
                     return true;
                 }
@@ -1192,11 +1166,11 @@
         }
 
         @Override
-        public Set<Command> getCommands_impl() {
+        public Set<SessionCommand2> getCommands_impl() {
             return getCommands();
         }
 
-        public Set<Command> getCommands() {
+        public Set<SessionCommand2> getCommands() {
             return Collections.unmodifiableSet(mCommands);
         }
 
@@ -1207,7 +1181,7 @@
         @Override
         public Bundle toBundle_impl() {
             ArrayList<Bundle> list = new ArrayList<>();
-            for (Command command : mCommands) {
+            for (SessionCommand2 command : mCommands) {
                 list.add(command.toBundle());
             }
             Bundle bundle = new Bundle();
@@ -1219,7 +1193,7 @@
          * @return new instance of CommandGroup from the bundle
          * @hide
          */
-        public static @Nullable CommandGroup fromBundle_impl(Context context, Bundle commands) {
+        public static @Nullable SessionCommandGroup2 fromBundle_impl(Bundle commands) {
             if (commands == null) {
                 return null;
             }
@@ -1227,14 +1201,14 @@
             if (list == null) {
                 return null;
             }
-            CommandGroup commandGroup = new CommandGroup(context);
+            SessionCommandGroup2 commandGroup = new SessionCommandGroup2();
             for (int i = 0; i < list.size(); i++) {
                 Parcelable parcelable = list.get(i);
                 if (!(parcelable instanceof Bundle)) {
                     continue;
                 }
                 Bundle commandBundle = (Bundle) parcelable;
-                Command command = Command.fromBundle(context, commandBundle);
+                SessionCommand2 command = SessionCommand2.fromBundle(commandBundle);
                 if (command != null) {
                     commandGroup.addCommand(command);
                 }
@@ -1319,19 +1293,19 @@
             return mControllerBinder.asBinder().equals(other.mControllerBinder.asBinder());
         }
 
-        public ControllerInfo getInstance() {
+        ControllerInfo getInstance() {
             return mInstance;
         }
 
-        public IBinder getId() {
+        IBinder getId() {
             return mControllerBinder.asBinder();
         }
 
-        public IMediaController2 getControllerBinder() {
+        IMediaController2 getControllerBinder() {
             return mControllerBinder;
         }
 
-        public static ControllerInfoImpl from(ControllerInfo controller) {
+        static ControllerInfoImpl from(ControllerInfo controller) {
             return (ControllerInfoImpl) controller.getProvider();
         }
     }
@@ -1349,13 +1323,13 @@
                 = "android.media.media_session2.command_button.enabled";
 
         private final CommandButton mInstance;
-        private Command mCommand;
+        private SessionCommand2 mCommand;
         private int mIconResId;
         private String mDisplayName;
         private Bundle mExtras;
         private boolean mEnabled;
 
-        public CommandButtonImpl(Context context, @Nullable Command command, int iconResId,
+        public CommandButtonImpl(@Nullable SessionCommand2 command, int iconResId,
                 @Nullable String displayName, Bundle extras, boolean enabled) {
             mCommand = command;
             mIconResId = iconResId;
@@ -1366,7 +1340,8 @@
         }
 
         @Override
-        public @Nullable Command getCommand_impl() {
+        public @Nullable
+        SessionCommand2 getCommand_impl() {
             return mCommand;
         }
 
@@ -1390,7 +1365,7 @@
             return mEnabled;
         }
 
-        public @NonNull Bundle toBundle() {
+        @NonNull Bundle toBundle() {
             Bundle bundle = new Bundle();
             bundle.putBundle(KEY_COMMAND, mCommand.toBundle());
             bundle.putInt(KEY_ICON_RES_ID, mIconResId);
@@ -1400,12 +1375,12 @@
             return bundle;
         }
 
-        public static @Nullable CommandButton fromBundle(Context context, Bundle bundle) {
+        static @Nullable CommandButton fromBundle(Bundle bundle) {
             if (bundle == null) {
                 return null;
             }
-            CommandButton.Builder builder = new CommandButton.Builder(context);
-            builder.setCommand(Command.fromBundle(context, bundle.getBundle(KEY_COMMAND)));
+            CommandButton.Builder builder = new CommandButton.Builder();
+            builder.setCommand(SessionCommand2.fromBundle(bundle.getBundle(KEY_COMMAND)));
             builder.setIconResId(bundle.getInt(KEY_ICON_RES_ID, 0));
             builder.setDisplayName(bundle.getString(KEY_DISPLAY_NAME));
             builder.setExtras(bundle.getBundle(KEY_EXTRAS));
@@ -1422,22 +1397,20 @@
          * Builder for {@link CommandButton}.
          */
         public static class BuilderImpl implements CommandButtonProvider.BuilderProvider {
-            private final Context mContext;
             private final CommandButton.Builder mInstance;
-            private Command mCommand;
+            private SessionCommand2 mCommand;
             private int mIconResId;
             private String mDisplayName;
             private Bundle mExtras;
             private boolean mEnabled;
 
-            public BuilderImpl(Context context, CommandButton.Builder instance) {
-                mContext = context;
+            public BuilderImpl(CommandButton.Builder instance) {
                 mInstance = instance;
                 mEnabled = true;
             }
 
             @Override
-            public CommandButton.Builder setCommand_impl(Command command) {
+            public CommandButton.Builder setCommand_impl(SessionCommand2 command) {
                 mCommand = command;
                 return mInstance;
             }
@@ -1477,8 +1450,8 @@
                     throw new IllegalStateException("Custom commands needs icon and"
                             + " and name to display");
                 }
-                return new CommandButtonImpl(
-                        mContext, mCommand, mIconResId, mDisplayName, mExtras, mEnabled).mInstance;
+                return new CommandButtonImpl(mCommand, mIconResId, mDisplayName, mExtras, mEnabled)
+                        .mInstance;
             }
         }
     }
@@ -1572,7 +1545,7 @@
                 mCallbackExecutor = mContext.getMainExecutor();
             }
             if (mCallback == null) {
-                mCallback = new SessionCallback(mContext) {};
+                mCallback = new SessionCallback() {};
             }
             return new MediaSession2Impl(mContext, mPlayer, mId, mPlaylistAgent,
                     mVolumeProvider, mSessionActivity, mCallbackExecutor, mCallback).getInstance();
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
index a3cb0c6..ec657d7 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
@@ -22,10 +22,9 @@
 import android.media.MediaItem2;
 import android.media.MediaLibraryService2.LibraryRoot;
 import android.media.MediaMetadata2;
-import android.media.MediaSession2;
-import android.media.MediaSession2.Command;
+import android.media.SessionCommand2;
 import android.media.MediaSession2.CommandButton;
-import android.media.MediaSession2.CommandGroup;
+import android.media.SessionCommandGroup2;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.Rating2;
 import android.media.VolumeProvider2;
@@ -64,7 +63,8 @@
     private static final String TAG = "MediaSession2Stub";
     private static final boolean DEBUG = true; // TODO(jaewan): Rename.
 
-    private static final SparseArray<Command> sCommandsForOnCommandRequest = new SparseArray<>();
+    private static final SparseArray<SessionCommand2> sCommandsForOnCommandRequest =
+            new SparseArray<>();
 
     private final Object mLock = new Object();
     private final WeakReference<MediaSession2Impl> mSession;
@@ -74,7 +74,8 @@
     @GuardedBy("mLock")
     private final Set<IBinder> mConnectingControllers = new HashSet<>();
     @GuardedBy("mLock")
-    private final ArrayMap<ControllerInfo, CommandGroup> mAllowedCommandGroupMap = new ArrayMap<>();
+    private final ArrayMap<ControllerInfo, SessionCommandGroup2> mAllowedCommandGroupMap =
+            new ArrayMap<>();
     @GuardedBy("mLock")
     private final ArrayMap<ControllerInfo, Set<String>> mSubscriptions = new ArrayMap<>();
 
@@ -83,11 +84,11 @@
 
         synchronized (sCommandsForOnCommandRequest) {
             if (sCommandsForOnCommandRequest.size() == 0) {
-                CommandGroupImpl group = new CommandGroupImpl(session.getContext());
+                CommandGroupImpl group = new CommandGroupImpl();
                 group.addAllPlaybackCommands();
                 group.addAllPlaylistCommands();
-                Set<Command> commands = group.getCommands();
-                for (Command command : commands) {
+                Set<SessionCommand2> commands = group.getCommands();
+                for (SessionCommand2 command : commands) {
                     sCommandsForOnCommandRequest.append(command.getCommandCode(), command);
                 }
             }
@@ -147,7 +148,7 @@
             if (controllerInfo == null) {
                 return null;
             }
-            CommandGroup allowedCommands = mAllowedCommandGroupMap.get(controllerInfo);
+            SessionCommandGroup2 allowedCommands = mAllowedCommandGroupMap.get(controllerInfo);
             if (allowedCommands == null) {
                 Log.w(TAG, "Controller with null allowed commands. Ignoring",
                         new IllegalStateException());
@@ -164,13 +165,13 @@
     }
 
     // Get controller if the command from caller to session is able to be handled.
-    private ControllerInfo getControllerIfAble(IMediaController2 caller, Command command) {
+    private ControllerInfo getControllerIfAble(IMediaController2 caller, SessionCommand2 command) {
         synchronized (mLock) {
             final ControllerInfo controllerInfo = getControllerIfAble(caller);
             if (controllerInfo == null) {
                 return null;
             }
-            CommandGroup allowedCommands = mAllowedCommandGroupMap.get(controllerInfo);
+            SessionCommandGroup2 allowedCommands = mAllowedCommandGroupMap.get(controllerInfo);
             if (allowedCommands == null) {
                 Log.w(TAG, "Controller with null allowed commands. Ignoring",
                         new IllegalStateException());
@@ -210,7 +211,7 @@
     private IMediaController2 getControllerBinderIfAble(ControllerInfo controller,
             int commandCode) {
         synchronized (mLock) {
-            CommandGroup allowedCommands = mAllowedCommandGroupMap.get(controller);
+            SessionCommandGroup2 allowedCommands = mAllowedCommandGroupMap.get(controller);
             if (allowedCommands == null) {
                 Log.w(TAG, "Controller with null allowed commands. Ignoring");
                 return null;
@@ -236,7 +237,7 @@
             if (getControllerIfAble(caller, commandCode) == null) {
                 return;
             }
-            Command command = sCommandsForOnCommandRequest.get(commandCode);
+            SessionCommand2 command = sCommandsForOnCommandRequest.get(commandCode);
             if (command != null) {
                 boolean accepted = session.getCallback().onCommandRequest(session.getInstance(),
                         controller, command);
@@ -256,13 +257,14 @@
     private void onBrowserCommand(@NonNull IMediaController2 caller,
             @NonNull LibrarySessionRunnable runnable) {
         final MediaLibrarySessionImpl session = getLibrarySession();
-        final ControllerInfo controller =
-                getControllerIfAble(caller, MediaSession2.COMMAND_CODE_BROWSER);
+        // TODO(jaewan): Consider command code
+        final ControllerInfo controller = getControllerIfAble(caller);
         if (session == null || controller == null) {
             return;
         }
         session.getCallbackExecutor().execute(() -> {
-            if (getControllerIfAble(caller, MediaSession2.COMMAND_CODE_BROWSER) == null) {
+            // TODO(jaewan): Consider command code
+            if (getControllerIfAble(caller) == null) {
                 return;
             }
             runnable.run(session, controller);
@@ -359,7 +361,7 @@
                 // instead of pending them.
                 mConnectingControllers.add(ControllerInfoImpl.from(controllerInfo).getId());
             }
-            CommandGroup allowedCommands = session.getCallback().onConnect(
+            SessionCommandGroup2 allowedCommands = session.getCallback().onConnect(
                     session.getInstance(), controllerInfo);
             // Don't reject connection for the request from trusted app.
             // Otherwise server will fail to retrieve session's information to dispatch
@@ -373,7 +375,7 @@
                 }
                 if (allowedCommands == null) {
                     // For trusted apps, send non-null allowed commands to keep connection.
-                    allowedCommands = new CommandGroup(context);
+                    allowedCommands = new SessionCommandGroup2();
                 }
                 synchronized (mLock) {
                     mConnectingControllers.remove(controllerImpl.getId());
@@ -397,7 +399,7 @@
                 final int shuffleMode = session.getInstance().getShuffleMode();
                 final PendingIntent sessionActivity = session.getSessionActivity();
                 final List<MediaItem2> playlist =
-                        allowedCommands.hasCommand(MediaSession2.COMMAND_CODE_PLAYLIST_GET_LIST)
+                        allowedCommands.hasCommand(SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST)
                                 ? session.getInstance().getPlaylist() : null;
                 final List<Bundle> playlistBundle;
                 if (playlist != null) {
@@ -455,27 +457,29 @@
     @Override
     public void setVolumeTo(final IMediaController2 caller, final int value, final int flags)
             throws RuntimeException {
-        onCommand(caller, MediaSession2.COMMAND_CODE_PLAYBACK_SET_VOLUME, (session, controller) -> {
-            VolumeProvider2 volumeProvider = session.getVolumeProvider();
-            if (volumeProvider == null) {
-                // TODO(jaewan): Set local stream volume
-            } else {
-                volumeProvider.onSetVolumeTo(value);
-            }
-        });
+        onCommand(caller, SessionCommand2.COMMAND_CODE_SET_VOLUME,
+                (session, controller) -> {
+                    VolumeProvider2 volumeProvider = session.getVolumeProvider();
+                    if (volumeProvider == null) {
+                        // TODO(jaewan): Set local stream volume
+                    } else {
+                        volumeProvider.onSetVolumeTo(value);
+                    }
+                });
     }
 
     @Override
     public void adjustVolume(IMediaController2 caller, int direction, int flags)
             throws RuntimeException {
-        onCommand(caller, MediaSession2.COMMAND_CODE_PLAYBACK_SET_VOLUME, (session, controller) -> {
-            VolumeProvider2 volumeProvider = session.getVolumeProvider();
-            if (volumeProvider == null) {
-                // TODO(jaewan): Adjust local stream volume
-            } else {
-                volumeProvider.onAdjustVolume(direction);
-            }
-        });
+        onCommand(caller, SessionCommand2.COMMAND_CODE_SET_VOLUME,
+                (session, controller) -> {
+                    VolumeProvider2 volumeProvider = session.getVolumeProvider();
+                    if (volumeProvider == null) {
+                        // TODO(jaewan): Adjust local stream volume
+                    } else {
+                        volumeProvider.onAdjustVolume(direction);
+                    }
+                });
     }
 
     @Override
@@ -483,25 +487,19 @@
             int commandCode, Bundle args) throws RuntimeException {
         onCommand(caller, commandCode, (session, controller) -> {
             switch (commandCode) {
-                case MediaSession2.COMMAND_CODE_PLAYBACK_PLAY:
+                case SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY:
                     session.getInstance().play();
                     break;
-                case MediaSession2.COMMAND_CODE_PLAYBACK_PAUSE:
+                case SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE:
                     session.getInstance().pause();
                     break;
-                case MediaSession2.COMMAND_CODE_PLAYBACK_STOP:
+                case SessionCommand2.COMMAND_CODE_PLAYBACK_STOP:
                     session.getInstance().stop();
                     break;
-                case MediaSession2.COMMAND_CODE_PLAYBACK_PREPARE:
+                case SessionCommand2.COMMAND_CODE_PLAYBACK_PREPARE:
                     session.getInstance().prepare();
                     break;
-                case MediaSession2.COMMAND_CODE_PLAYBACK_FAST_FORWARD:
-                    session.getInstance().fastForward();
-                    break;
-                case MediaSession2.COMMAND_CODE_PLAYBACK_REWIND:
-                    session.getInstance().rewind();
-                    break;
-                case MediaSession2.COMMAND_CODE_PLAYBACK_SEEK_TO:
+                case SessionCommand2.COMMAND_CODE_PLAYBACK_SEEK_TO:
                     session.getInstance().seekTo(args.getLong(ARGUMENT_KEY_POSITION));
                     break;
                 default:
@@ -517,7 +515,7 @@
         if (session == null) {
             return;
         }
-        final Command command = Command.fromBundle(session.getContext(), commandBundle);
+        final SessionCommand2 command = SessionCommand2.fromBundle(commandBundle);
         if (command == null) {
             Log.w(TAG, "sendCustomCommand(): Ignoring null command from "
                     + getControllerIfAble(caller));
@@ -539,32 +537,35 @@
     @Override
     public void prepareFromUri(final IMediaController2 caller, final Uri uri,
             final Bundle extras) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_SESSION_PREPARE_FROM_URI, (session, controller) -> {
-            if (uri == null) {
-                Log.w(TAG, "prepareFromUri(): Ignoring null uri from " + controller);
-                return;
-            }
-            session.getCallback().onPrepareFromUri(session.getInstance(), controller, uri, extras);
-        });
+        onCommand(caller, SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_URI,
+                (session, controller) -> {
+                    if (uri == null) {
+                        Log.w(TAG, "prepareFromUri(): Ignoring null uri from " + controller);
+                        return;
+                    }
+                    session.getCallback().onPrepareFromUri(session.getInstance(), controller, uri,
+                            extras);
+                });
     }
 
     @Override
     public void prepareFromSearch(final IMediaController2 caller, final String query,
             final Bundle extras) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH, (session, controller) -> {
-            if (TextUtils.isEmpty(query)) {
-                Log.w(TAG, "prepareFromSearch(): Ignoring empty query from " + controller);
-                return;
-            }
-            session.getCallback().onPrepareFromSearch(session.getInstance(),
-                    controller, query, extras);
-        });
+        onCommand(caller, SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH,
+                (session, controller) -> {
+                    if (TextUtils.isEmpty(query)) {
+                        Log.w(TAG, "prepareFromSearch(): Ignoring empty query from " + controller);
+                        return;
+                    }
+                    session.getCallback().onPrepareFromSearch(session.getInstance(),
+                            controller, query, extras);
+                });
     }
 
     @Override
     public void prepareFromMediaId(final IMediaController2 caller, final String mediaId,
             final Bundle extras) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID,
+        onCommand(caller, SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID,
                 (session, controller) -> {
             if (mediaId == null) {
                 Log.w(TAG, "prepareFromMediaId(): Ignoring null mediaId from " + controller);
@@ -578,69 +579,75 @@
     @Override
     public void playFromUri(final IMediaController2 caller, final Uri uri,
             final Bundle extras) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_SESSION_PLAY_FROM_URI, (session, controller) -> {
-            if (uri == null) {
-                Log.w(TAG, "playFromUri(): Ignoring null uri from " + controller);
-                return;
-            }
-            session.getCallback().onPlayFromUri(session.getInstance(), controller, uri, extras);
-        });
+        onCommand(caller, SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_URI,
+                (session, controller) -> {
+                    if (uri == null) {
+                        Log.w(TAG, "playFromUri(): Ignoring null uri from " + controller);
+                        return;
+                    }
+                    session.getCallback().onPlayFromUri(session.getInstance(), controller, uri,
+                            extras);
+                });
     }
 
     @Override
     public void playFromSearch(final IMediaController2 caller, final String query,
             final Bundle extras) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_SESSION_PLAY_FROM_SEARCH, (session, controller) -> {
-            if (TextUtils.isEmpty(query)) {
-                Log.w(TAG, "playFromSearch(): Ignoring empty query from " + controller);
-                return;
-            }
-            session.getCallback().onPlayFromSearch(session.getInstance(),
-                    controller, query, extras);
-        });
+        onCommand(caller, SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_SEARCH,
+                (session, controller) -> {
+                    if (TextUtils.isEmpty(query)) {
+                        Log.w(TAG, "playFromSearch(): Ignoring empty query from " + controller);
+                        return;
+                    }
+                    session.getCallback().onPlayFromSearch(session.getInstance(),
+                            controller, query, extras);
+                });
     }
 
     @Override
     public void playFromMediaId(final IMediaController2 caller, final String mediaId,
             final Bundle extras) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID, (session, controller) -> {
-            if (mediaId == null) {
-                Log.w(TAG, "playFromMediaId(): Ignoring null mediaId from " + controller);
-                return;
-            }
-            session.getCallback().onPlayFromMediaId(session.getInstance(),
-                    controller, mediaId, extras);
-        });
+        onCommand(caller, SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID,
+                (session, controller) -> {
+                    if (mediaId == null) {
+                        Log.w(TAG, "playFromMediaId(): Ignoring null mediaId from " + controller);
+                        return;
+                    }
+                    session.getCallback().onPlayFromMediaId(session.getInstance(), controller,
+                            mediaId, extras);
+                });
     }
 
     @Override
     public void setRating(final IMediaController2 caller, final String mediaId,
             final Bundle ratingBundle) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_SESSION_SET_RATING, (session, controller) -> {
-            if (mediaId == null) {
-                Log.w(TAG, "setRating(): Ignoring null mediaId from " + controller);
-                return;
-            }
-            if (ratingBundle == null) {
-                Log.w(TAG, "setRating(): Ignoring null ratingBundle from " + controller);
-                return;
-            }
-            Rating2 rating = Rating2Impl.fromBundle(session.getContext(), ratingBundle);
-            if (rating == null) {
-                if (ratingBundle == null) {
-                    Log.w(TAG, "setRating(): Ignoring null rating from " + controller);
-                    return;
-                }
-                return;
-            }
-            session.getCallback().onSetRating(session.getInstance(), controller, mediaId, rating);
-        });
+        onCommand(caller, SessionCommand2.COMMAND_CODE_SESSION_SET_RATING,
+                (session, controller) -> {
+                    if (mediaId == null) {
+                        Log.w(TAG, "setRating(): Ignoring null mediaId from " + controller);
+                        return;
+                    }
+                    if (ratingBundle == null) {
+                        Log.w(TAG, "setRating(): Ignoring null ratingBundle from " + controller);
+                        return;
+                    }
+                    Rating2 rating = Rating2.fromBundle(ratingBundle);
+                    if (rating == null) {
+                        if (ratingBundle == null) {
+                            Log.w(TAG, "setRating(): Ignoring null rating from " + controller);
+                            return;
+                        }
+                        return;
+                    }
+                    session.getCallback().onSetRating(session.getInstance(), controller, mediaId,
+                            rating);
+                });
     }
 
     @Override
     public void setPlaylist(final IMediaController2 caller, final List<Bundle> playlist,
             final Bundle metadata) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_PLAYLIST_SET_LIST, (session, controller) -> {
+        onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SET_LIST, (session, controller) -> {
             if (playlist == null) {
                 Log.w(TAG, "setPlaylist(): Ignoring null playlist from " + controller);
                 return;
@@ -648,41 +655,39 @@
             List<MediaItem2> list = new ArrayList<>();
             for (int i = 0; i < playlist.size(); i++) {
                 // Recreates UUID in the playlist
-                MediaItem2 item = MediaItem2Impl.fromBundle(
-                        session.getContext(), playlist.get(i), null);
+                MediaItem2 item = MediaItem2Impl.fromBundle(playlist.get(i), null);
                 if (item != null) {
                     list.add(item);
                 }
             }
-            session.getInstance().setPlaylist(list,
-                    MediaMetadata2.fromBundle(session.getContext(), metadata));
+            session.getInstance().setPlaylist(list, MediaMetadata2.fromBundle(metadata));
         });
     }
 
     @Override
     public void updatePlaylistMetadata(final IMediaController2 caller, final Bundle metadata) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_PLAYLIST_SET_LIST_METADATA,
+        onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SET_LIST_METADATA,
                 (session, controller) -> {
-            session.getInstance().updatePlaylistMetadata(
-                    MediaMetadata2.fromBundle(session.getContext(), metadata));
+            session.getInstance().updatePlaylistMetadata(MediaMetadata2.fromBundle(metadata));
         });
     }
 
     @Override
     public void addPlaylistItem(IMediaController2 caller, int index, Bundle mediaItem) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_PLAYLIST_ADD_ITEM, (session, controller) -> {
-            // Resets the UUID from the incoming media id, so controller may reuse a media item
-            // multiple times for addPlaylistItem.
-            session.getInstance().addPlaylistItem(index,
-                    MediaItem2Impl.fromBundle(session.getContext(), mediaItem, null));
-        });
+        onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_ADD_ITEM,
+                (session, controller) -> {
+                    // Resets the UUID from the incoming media id, so controller may reuse a media
+                    // item multiple times for addPlaylistItem.
+                    session.getInstance().addPlaylistItem(index,
+                            MediaItem2Impl.fromBundle(mediaItem, null));
+                });
     }
 
     @Override
     public void removePlaylistItem(IMediaController2 caller, Bundle mediaItem) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_PLAYLIST_REMOVE_ITEM,
+        onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_REMOVE_ITEM,
                 (session, controller) -> {
-            MediaItem2 item = MediaItem2.fromBundle(session.getContext(), mediaItem);
+            MediaItem2 item = MediaItem2.fromBundle(mediaItem);
             // Note: MediaItem2 has hidden UUID to identify it across the processes.
             session.getInstance().removePlaylistItem(item);
         });
@@ -690,32 +695,31 @@
 
     @Override
     public void replacePlaylistItem(IMediaController2 caller, int index, Bundle mediaItem) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_PLAYLIST_REPLACE_ITEM,
+        onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_REPLACE_ITEM,
                 (session, controller) -> {
                     // Resets the UUID from the incoming media id, so controller may reuse a media
                     // item multiple times for replacePlaylistItem.
                     session.getInstance().replacePlaylistItem(index,
-                            MediaItem2Impl.fromBundle(session.getContext(), mediaItem, null));
+                            MediaItem2Impl.fromBundle(mediaItem, null));
                 });
     }
 
     @Override
     public void skipToPlaylistItem(IMediaController2 caller, Bundle mediaItem) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM,
+        onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM,
                 (session, controller) -> {
                     if (mediaItem == null) {
                         Log.w(TAG, "skipToPlaylistItem(): Ignoring null mediaItem from "
                                 + controller);
                     }
                     // Note: MediaItem2 has hidden UUID to identify it across the processes.
-                    session.getInstance().skipToPlaylistItem(
-                            MediaItem2.fromBundle(session.getContext(), mediaItem));
+                    session.getInstance().skipToPlaylistItem(MediaItem2.fromBundle(mediaItem));
                 });
     }
 
     @Override
     public void skipToPreviousItem(IMediaController2 caller) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_PLAYLIST_SKIP_PREV_ITEM,
+        onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SKIP_PREV_ITEM,
                 (session, controller) -> {
                     session.getInstance().skipToPreviousItem();
                 });
@@ -723,7 +727,7 @@
 
     @Override
     public void skipToNextItem(IMediaController2 caller) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_PLAYLIST_SKIP_NEXT_ITEM,
+        onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SKIP_NEXT_ITEM,
                 (session, controller) -> {
                     session.getInstance().skipToNextItem();
                 });
@@ -731,7 +735,7 @@
 
     @Override
     public void setRepeatMode(IMediaController2 caller, int repeatMode) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE,
+        onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE,
                 (session, controller) -> {
                     session.getInstance().setRepeatMode(repeatMode);
                 });
@@ -739,7 +743,7 @@
 
     @Override
     public void setShuffleMode(IMediaController2 caller, int shuffleMode) {
-        onCommand(caller, MediaSession2.COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE,
+        onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE,
                 (session, controller) -> {
                     session.getInstance().setShuffleMode(shuffleMode);
                 });
@@ -922,6 +926,7 @@
         });
     }
 
+    // TODO(jaewan): Rename
     public void notifyPositionChangedNotLocked(long eventTimeMs, long positionMs) {
         notifyAll((controller, iController) -> {
             iController.onPositionChanged(eventTimeMs, positionMs);
@@ -971,10 +976,10 @@
         final Bundle metadataBundle = (metadata == null) ? null : metadata.toBundle();
         notifyAll((controller, iController) -> {
             if (getControllerBinderIfAble(controller,
-                    MediaSession2.COMMAND_CODE_PLAYLIST_GET_LIST) != null) {
+                    SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST) != null) {
                 iController.onPlaylistChanged(bundleList, metadataBundle);
             } else if (getControllerBinderIfAble(controller,
-                    MediaSession2.COMMAND_CODE_PLAYLIST_GET_LIST_METADATA) != null) {
+                    SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST_METADATA) != null) {
                 iController.onPlaylistMetadataChanged(metadataBundle);
             }
         });
@@ -982,7 +987,7 @@
 
     public void notifyPlaylistMetadataChangedNotLocked(MediaMetadata2 metadata) {
         final Bundle metadataBundle = (metadata == null) ? null : metadata.toBundle();
-        notifyAll(MediaSession2.COMMAND_CODE_PLAYLIST_GET_LIST_METADATA,
+        notifyAll(SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST_METADATA,
                 (unused, iController) -> {
                     iController.onPlaylistMetadataChanged(metadataBundle);
                 });
@@ -1008,7 +1013,7 @@
         });
     }
 
-    public void setAllowedCommands(ControllerInfo controller, CommandGroup commands) {
+    public void setAllowedCommands(ControllerInfo controller, SessionCommandGroup2 commands) {
         synchronized (mLock) {
             mAllowedCommandGroupMap.put(controller, commands);
         }
@@ -1017,7 +1022,7 @@
         });
     }
 
-    public void sendCustomCommand(ControllerInfo controller, Command command, Bundle args,
+    public void sendCustomCommand(ControllerInfo controller, SessionCommand2 command, Bundle args,
             ResultReceiver receiver) {
         if (receiver != null && controller == null) {
             throw new IllegalArgumentException("Controller shouldn't be null if result receiver is"
@@ -1032,7 +1037,7 @@
         });
     }
 
-    public void sendCustomCommand(Command command, Bundle args) {
+    public void sendCustomCommand(SessionCommand2 command, Bundle args) {
         if (command == null) {
             throw new IllegalArgumentException("command shouldn't be null");
         }
diff --git a/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
index a0123b5..c33eb65 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
@@ -147,8 +147,8 @@
         private int mNotificationId;
         private Notification mNotification;
 
-        public MediaNotificationImpl(Context context, MediaNotification instance,
-                int notificationId, Notification notification) {
+        public MediaNotificationImpl(MediaNotification instance, int notificationId,
+                Notification notification) {
             if (notification == null) {
                 throw new IllegalArgumentException("notification shouldn't be null");
             }
diff --git a/packages/MediaComponents/src/com/android/media/Rating2Impl.java b/packages/MediaComponents/src/com/android/media/Rating2Impl.java
index 68e104a..d558129 100644
--- a/packages/MediaComponents/src/com/android/media/Rating2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/Rating2Impl.java
@@ -39,7 +39,7 @@
     private final int mRatingStyle;
     private final float mRatingValue;
 
-    private Rating2Impl(Context context, @Style int ratingStyle, float rating) {
+    private Rating2Impl(@Style int ratingStyle, float rating) {
         mRatingStyle = ratingStyle;
         mRatingValue = rating;
         mInstance = new Rating2(this);
@@ -66,16 +66,15 @@
         return Objects.hash(mRatingStyle, mRatingValue);
     }
 
-    public Rating2 getInstance() {
+    Rating2 getInstance() {
         return mInstance;
     }
 
-    public static Rating2 fromBundle(Context context, Bundle bundle) {
+    public static Rating2 fromBundle_impl(Bundle bundle) {
         if (bundle == null) {
             return null;
         }
-        return new Rating2Impl(context, bundle.getInt(KEY_STYLE), bundle.getFloat(KEY_VALUE))
-                .getInstance();
+        return new Rating2Impl(bundle.getInt(KEY_STYLE), bundle.getFloat(KEY_VALUE)).getInstance();
     }
 
     public Bundle toBundle_impl() {
@@ -85,7 +84,7 @@
         return bundle;
     }
 
-    public static Rating2 newUnratedRating(Context context, @Style int ratingStyle) {
+    public static Rating2 newUnratedRating_impl(@Style int ratingStyle) {
         switch(ratingStyle) {
             case RATING_HEART:
             case RATING_THUMB_UP_DOWN:
@@ -93,22 +92,21 @@
             case RATING_4_STARS:
             case RATING_5_STARS:
             case RATING_PERCENTAGE:
-                return new Rating2Impl(context, ratingStyle, RATING_NOT_RATED).getInstance();
+                return new Rating2Impl(ratingStyle, RATING_NOT_RATED).getInstance();
             default:
                 return null;
         }
     }
 
-    public static Rating2 newHeartRating(Context context, boolean hasHeart) {
-        return new Rating2Impl(context, RATING_HEART, hasHeart ? 1.0f : 0.0f).getInstance();
+    public static Rating2 newHeartRating_impl(boolean hasHeart) {
+        return new Rating2Impl(RATING_HEART, hasHeart ? 1.0f : 0.0f).getInstance();
     }
 
-    public static Rating2 newThumbRating(Context context, boolean thumbIsUp) {
-        return new Rating2Impl(context, RATING_THUMB_UP_DOWN, thumbIsUp ? 1.0f : 0.0f)
-                .getInstance();
+    public static Rating2 newThumbRating_impl(boolean thumbIsUp) {
+        return new Rating2Impl(RATING_THUMB_UP_DOWN, thumbIsUp ? 1.0f : 0.0f).getInstance();
     }
 
-    public static Rating2 newStarRating(Context context, int starRatingStyle, float starRating) {
+    public static Rating2 newStarRating_impl(int starRatingStyle, float starRating) {
         float maxRating = RATING_NOT_RATED;
         switch(starRatingStyle) {
             case RATING_3_STARS:
@@ -128,15 +126,15 @@
             Log.e(TAG, "Trying to set out of range star-based rating");
             return null;
         }
-        return new Rating2Impl(context, starRatingStyle, starRating).getInstance();
+        return new Rating2Impl(starRatingStyle, starRating).getInstance();
     }
 
-    public static Rating2 newPercentageRating(Context context, float percent) {
+    public static Rating2 newPercentageRating_impl(float percent) {
         if ((percent < 0.0f) || (percent > 100.0f)) {
             Log.e(TAG, "Invalid percentage-based rating value");
             return null;
         } else {
-            return new Rating2Impl(context, RATING_PERCENTAGE, percent).getInstance();
+            return new Rating2Impl(RATING_PERCENTAGE, percent).getInstance();
         }
     }
 
diff --git a/packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java b/packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java
index dfbe56a..1c570aa 100644
--- a/packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java
+++ b/packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.Context;
 import android.media.DataSourceDesc;
 import android.media.MediaItem2;
 import android.media.MediaMetadata2;
@@ -133,9 +132,8 @@
         }
     }
 
-    public SessionPlaylistAgent(@NonNull Context context, @NonNull MediaSession2Impl sessionImpl,
+    public SessionPlaylistAgent(@NonNull MediaSession2Impl sessionImpl,
             @NonNull MediaPlayerBase player) {
-        super(context);
         if (sessionImpl == null) {
             throw new IllegalArgumentException("sessionImpl shouldn't be null");
         }
diff --git a/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java b/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
index 723622e..a5cf8c4 100644
--- a/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
@@ -98,8 +98,8 @@
         mSessionBinder = null;
     }
 
-    public SessionToken2Impl(Context context, int uid, int type,
-            String packageName, String serviceName, String id, IMediaSession2 sessionBinder) {
+    SessionToken2Impl(int uid, int type, String packageName, String serviceName, String id,
+            IMediaSession2 sessionBinder) {
         // TODO(jaewan): Add sanity check (b/73863865)
         mUid = uid;
         mType = type;
@@ -168,15 +168,15 @@
         return mType;
     }
 
-    public String getServiceName() {
+    String getServiceName() {
         return mServiceName;
     }
 
-    public IMediaSession2 getSessionBinder() {
+    IMediaSession2 getSessionBinder() {
         return mSessionBinder;
     }
 
-    public static SessionToken2 fromBundle_impl(Context context, Bundle bundle) {
+    public static SessionToken2 fromBundle_impl(Bundle bundle) {
         if (bundle == null) {
             return null;
         }
@@ -207,7 +207,7 @@
         if (TextUtils.isEmpty(packageName) || id == null) {
             throw new IllegalArgumentException("Package name nor ID cannot be null.");
         }
-        return new SessionToken2Impl(context, uid, type, packageName, serviceName, id,
+        return new SessionToken2Impl(uid, type, packageName, serviceName, id,
                 sessionBinder != null ? IMediaSession2.Stub.asInterface(sessionBinder) : null)
                 .getInstance();
     }
@@ -254,7 +254,7 @@
                 + " service=" + mServiceName + " binder=" + mSessionBinder + "}";
     }
 
-    public static SessionToken2Impl from(SessionToken2 token) {
+    static SessionToken2Impl from(SessionToken2 token) {
         return ((SessionToken2Impl) token.getProvider());
     }
 }
diff --git a/packages/MediaComponents/src/com/android/media/VolumeProvider2Impl.java b/packages/MediaComponents/src/com/android/media/VolumeProvider2Impl.java
index 156bcae..bf22e1b 100644
--- a/packages/MediaComponents/src/com/android/media/VolumeProvider2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/VolumeProvider2Impl.java
@@ -19,13 +19,10 @@
 import static android.media.VolumeProvider2.VOLUME_CONTROL_FIXED;
 import static android.media.VolumeProvider2.VOLUME_CONTROL_RELATIVE;
 
-import android.content.Context;
 import android.media.VolumeProvider2;
 import android.media.update.VolumeProvider2Provider;
 
 public class VolumeProvider2Impl implements VolumeProvider2Provider {
-
-    private final Context mContext;
     private final VolumeProvider2 mInstance;
     private final int mControlType;
     private final int mMaxVolume;
@@ -33,7 +30,7 @@
     private int mCurrentVolume;
     private Callback mCallback;
 
-    public VolumeProvider2Impl(Context context, VolumeProvider2 instance,
+    public VolumeProvider2Impl(VolumeProvider2 instance,
             @VolumeProvider2.ControlType int controlType, int maxVolume, int currentVolume) {
         if (controlType != VOLUME_CONTROL_FIXED && controlType != VOLUME_CONTROL_RELATIVE
                 && controlType != VOLUME_CONTROL_ABSOLUTE) {
@@ -47,7 +44,6 @@
             throw new IllegalArgumentException("currentVolume shouldn't be greater than maxVolume"
                     + ", maxVolume=" + maxVolume + ", currentVolume=" + currentVolume);
         }
-        mContext = context;
         mInstance = instance;
         mControlType = controlType;
         mMaxVolume = maxVolume;
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
index 05a54d5..d7be549 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
@@ -31,8 +31,8 @@
 import android.media.MediaMetadata2;
 import android.media.MediaPlaylistAgent;
 import android.media.MediaSession2;
-import android.media.MediaSession2.Command;
-import android.media.MediaSession2.CommandGroup;
+import android.media.SessionCommand2;
+import android.media.SessionCommandGroup2;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSession2.SessionCallback;
 import android.media.MediaSessionService2;
@@ -85,7 +85,7 @@
 public final class ApiFactory implements StaticProvider {
     private ApiFactory() { }
 
-    public static ApiFactory initialize(ApplicationInfo updatableInfo) {
+    public static StaticProvider initialize(ApplicationInfo updatableInfo) {
         ApiHelper.initialize(updatableInfo);
         return new ApiFactory();
     }
@@ -105,7 +105,7 @@
 
     @Override
     public MediaSession2Provider.CommandProvider createMediaSession2Command(
-            Command instance, int commandCode, String action, Bundle extra) {
+            SessionCommand2 instance, int commandCode, String action, Bundle extra) {
         if (action == null && extra == null) {
             return new MediaSession2Impl.CommandImpl(instance, commandCode);
         }
@@ -113,20 +113,20 @@
     }
 
     @Override
-    public Command fromBundle_MediaSession2Command(Context context, Bundle command) {
-        return MediaSession2Impl.CommandImpl.fromBundle_impl(context, command);
+    public SessionCommand2 fromBundle_MediaSession2Command(Bundle command) {
+        return MediaSession2Impl.CommandImpl.fromBundle_impl(command);
     }
 
     @Override
     public MediaSession2Provider.CommandGroupProvider createMediaSession2CommandGroup(
-            Context context, CommandGroup instance, CommandGroup other) {
-        return new MediaSession2Impl.CommandGroupImpl(context, instance,
+            SessionCommandGroup2 instance, SessionCommandGroup2 other) {
+        return new MediaSession2Impl.CommandGroupImpl(instance,
                 (other == null) ? null : other.getProvider());
     }
 
     @Override
-    public CommandGroup fromBundle_MediaSession2CommandGroup(Context context, Bundle commands) {
-        return MediaSession2Impl.CommandGroupImpl.fromBundle_impl(context, commands);
+    public SessionCommandGroup2 fromBundle_MediaSession2CommandGroup(Bundle commands) {
+        return MediaSession2Impl.CommandGroupImpl.fromBundle_impl(commands);
     }
 
     @Override
@@ -138,9 +138,9 @@
     }
 
     @Override
-    public BuilderProvider createMediaSession2CommandButtonBuilder(Context context,
+    public BuilderProvider createMediaSession2CommandButtonBuilder(
             MediaSession2.CommandButton.Builder instance) {
-        return new MediaSession2Impl.CommandButtonImpl.BuilderImpl(context, instance);
+        return new MediaSession2Impl.CommandButtonImpl.BuilderImpl(instance);
     }
 
     public BuilderBaseProvider<MediaSession2, SessionCallback> createMediaSession2Builder(
@@ -149,21 +149,19 @@
     }
 
     @Override
-    public MediaSessionService2Provider createMediaSessionService2(
-            MediaSessionService2 instance) {
+    public MediaSessionService2Provider createMediaSessionService2(MediaSessionService2 instance) {
         return new MediaSessionService2Impl(instance);
     }
 
     @Override
-    public MediaNotificationProvider createMediaSessionService2MediaNotification(Context context,
+    public MediaNotificationProvider createMediaSessionService2MediaNotification(
             MediaNotification instance, int notificationId, Notification notification) {
         return new MediaSessionService2Impl.MediaNotificationImpl(
-                context, instance, notificationId, notification);
+                instance, notificationId, notification);
     }
 
     @Override
-    public MediaSessionService2Provider createMediaLibraryService2(
-            MediaLibraryService2 instance) {
+    public MediaSessionService2Provider createMediaLibraryService2(MediaLibraryService2 instance) {
         return new MediaLibraryService2Impl(instance);
     }
 
@@ -177,9 +175,9 @@
     }
 
     @Override
-    public LibraryRootProvider createMediaLibraryService2LibraryRoot(Context context,
+    public LibraryRootProvider createMediaLibraryService2LibraryRoot(
             LibraryRoot instance, String rootId, Bundle extras) {
-        return new LibraryRootImpl(context, instance, rootId, extras);
+        return new LibraryRootImpl(instance, rootId, extras);
     }
 
     @Override
@@ -203,77 +201,76 @@
     }
 
     @Override
-    public SessionToken2 fromBundle_SessionToken2(Context context, Bundle bundle) {
-        return SessionToken2Impl.fromBundle_impl(context, bundle);
+    public SessionToken2 fromBundle_SessionToken2(Bundle bundle) {
+        return SessionToken2Impl.fromBundle_impl(bundle);
     }
 
     @Override
-    public MediaItem2Provider.BuilderProvider createMediaItem2Builder(
-            Context context, MediaItem2.Builder instance, int flags) {
-        return new MediaItem2Impl.BuilderImpl(context, instance, flags);
+    public MediaItem2Provider.BuilderProvider createMediaItem2Builder(MediaItem2.Builder instance,
+            int flags) {
+        return new MediaItem2Impl.BuilderImpl(instance, flags);
     }
 
     @Override
-    public MediaItem2 fromBundle_MediaItem2(Context context, Bundle bundle) {
-        return MediaItem2Impl.fromBundle(context, bundle);
+    public MediaItem2 fromBundle_MediaItem2(Bundle bundle) {
+        return MediaItem2Impl.fromBundle_impl(bundle);
     }
 
     @Override
-    public VolumeProvider2Provider createVolumeProvider2(Context context, VolumeProvider2 instance,
-            int controlType, int maxVolume, int currentVolume) {
-        return new VolumeProvider2Impl(context, instance, controlType, maxVolume, currentVolume);
+    public VolumeProvider2Provider createVolumeProvider2(VolumeProvider2 instance, int controlType,
+            int maxVolume, int currentVolume) {
+        return new VolumeProvider2Impl(instance, controlType, maxVolume, currentVolume);
     }
 
     @Override
-    public MediaMetadata2 fromBundle_MediaMetadata2(Context context, Bundle bundle) {
-        return MediaMetadata2Impl.fromBundle(context, bundle);
+    public MediaMetadata2 fromBundle_MediaMetadata2(Bundle bundle) {
+        return MediaMetadata2Impl.fromBundle_impl(bundle);
     }
 
     @Override
     public MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
-            Context context, MediaMetadata2.Builder instance) {
-        return new MediaMetadata2Impl.BuilderImpl(context, instance);
+            MediaMetadata2.Builder instance) {
+        return new MediaMetadata2Impl.BuilderImpl(instance);
     }
 
     @Override
     public MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
-            Context context, MediaMetadata2.Builder instance, MediaMetadata2 source) {
-        return new MediaMetadata2Impl.BuilderImpl(context, instance, source);
+            MediaMetadata2.Builder instance, MediaMetadata2 source) {
+        return new MediaMetadata2Impl.BuilderImpl(instance, source);
     }
 
     @Override
-    public Rating2 fromBundle_Rating2(Context context, Bundle bundle) {
-        return Rating2Impl.fromBundle(context, bundle);
+    public Rating2 fromBundle_Rating2(Bundle bundle) {
+        return Rating2Impl.fromBundle_impl(bundle);
     }
 
     @Override
-    public Rating2 newUnratedRating_Rating2(Context context, int ratingStyle) {
-        return Rating2Impl.newUnratedRating(context, ratingStyle);
+    public Rating2 newUnratedRating_Rating2(int ratingStyle) {
+        return Rating2Impl.newUnratedRating_impl(ratingStyle);
     }
 
     @Override
-    public Rating2 newHeartRating_Rating2(Context context, boolean hasHeart) {
-        return Rating2Impl.newHeartRating(context, hasHeart);
+    public Rating2 newHeartRating_Rating2(boolean hasHeart) {
+        return Rating2Impl.newHeartRating_impl(hasHeart);
     }
 
     @Override
-    public Rating2 newThumbRating_Rating2(Context context, boolean thumbIsUp) {
-        return Rating2Impl.newThumbRating(context, thumbIsUp);
+    public Rating2 newThumbRating_Rating2(boolean thumbIsUp) {
+        return Rating2Impl.newThumbRating_impl(thumbIsUp);
     }
 
     @Override
-    public Rating2 newStarRating_Rating2(Context context, int starRatingStyle, float starRating) {
-        return Rating2Impl.newStarRating(context, starRatingStyle, starRating);
+    public Rating2 newStarRating_Rating2(int starRatingStyle, float starRating) {
+        return Rating2Impl.newStarRating_impl(starRatingStyle, starRating);
     }
 
     @Override
-    public Rating2 newPercentageRating_Rating2(Context context, float percent) {
-        return Rating2Impl.newPercentageRating(context, percent);
+    public Rating2 newPercentageRating_Rating2(float percent) {
+        return Rating2Impl.newPercentageRating_impl(percent);
     }
 
     @Override
-    public MediaPlaylistAgentProvider createMediaPlaylistAgent(Context context,
-            MediaPlaylistAgent instance) {
-        return new MediaPlaylistAgentImpl(context, instance);
+    public MediaPlaylistAgentProvider createMediaPlaylistAgent(MediaPlaylistAgent instance) {
+        return new MediaPlaylistAgentImpl(instance);
     }
 }
diff --git a/packages/MediaComponents/tests/src/com/android/media/SessionPlaylistAgentTest.java b/packages/MediaComponents/tests/src/com/android/media/SessionPlaylistAgentTest.java
index 55a34fd..beb0848 100644
--- a/packages/MediaComponents/tests/src/com/android/media/SessionPlaylistAgentTest.java
+++ b/packages/MediaComponents/tests/src/com/android/media/SessionPlaylistAgentTest.java
@@ -240,7 +240,7 @@
 
         mSessionImpl = mock(MediaSession2Impl.class);
         mDataSourceHelper = new MyDataSourceHelper();
-        mAgent = new SessionPlaylistAgent(mContext, mSessionImpl, mPlayer);
+        mAgent = new SessionPlaylistAgent(mSessionImpl, mPlayer);
         mAgent.setOnDataSourceMissingHelper(mDataSourceHelper);
         mEventCallback = new MyPlaylistEventCallback(mWaitLock);
         mAgent.registerPlaylistEventCallback(mHandlerExecutor, mEventCallback);
@@ -629,13 +629,13 @@
     }
 
     private MediaItem2 generateMediaItemWithoutDataSourceDesc(int key) {
-        return new MediaItem2.Builder(mContext, 0)
+        return new MediaItem2.Builder(0)
                 .setMediaId("TEST_MEDIA_ID_WITHOUT_DSD_" + key)
                 .build();
     }
 
     private MediaItem2 generateMediaItem(int key) {
-        return new MediaItem2.Builder(mContext, 0)
+        return new MediaItem2.Builder(0)
                 .setMediaId("TEST_MEDIA_ID_" + key)
                 .build();
     }
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 90a5a0f..5d90408 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -273,7 +273,7 @@
 void AudioPolicyService::NotificationClient::onDynamicPolicyMixStateUpdate(
         const String8& regId, int32_t state)
 {
-    if (mAudioPolicyServiceClient != 0 && mUid < AID_APP_START) {
+    if (mAudioPolicyServiceClient != 0 && (mUid % AID_USER_OFFSET) < AID_APP_START) {
         mAudioPolicyServiceClient->onDynamicPolicyMixStateUpdate(regId, state);
     }
 }
@@ -283,7 +283,7 @@
         const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
         audio_patch_handle_t patchHandle)
 {
-    if (mAudioPolicyServiceClient != 0 && mUid < AID_APP_START) {
+    if (mAudioPolicyServiceClient != 0 && (mUid % AID_USER_OFFSET) < AID_APP_START) {
         mAudioPolicyServiceClient->onRecordingConfigurationUpdate(event, clientInfo,
                 clientConfig, deviceConfig, patchHandle);
     }
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;