Merge "AML: Make UserHandle.myUserId() available"
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index 404c537..babdc7a 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -37,6 +37,7 @@
 
 const int64_t kTimeoutWaitForOutputUs = 500000; // 0.5 seconds
 const int64_t kTimeoutWaitForInputUs = 5000; // 5 milliseconds
+const int kTimeoutMaxRetries = 20;
 
 //static
 sp<SimpleDecodingSource> SimpleDecodingSource::Create(
@@ -242,7 +243,7 @@
         return ERROR_END_OF_STREAM;
     }
 
-    for (int retries = 0; ++retries; ) {
+    for (int retries = 0; retries < kTimeoutMaxRetries; ++retries) {
         // If we fill all available input buffers, we should expect that
         // the codec produces at least one output buffer. Also, the codec
         // should produce an output buffer in at most 1 seconds. Retry a
diff --git a/packages/MediaComponents/Android.mk b/packages/MediaComponents/Android.mk
deleted file mode 100644
index fff3a62..0000000
--- a/packages/MediaComponents/Android.mk
+++ /dev/null
@@ -1,70 +0,0 @@
-#
-# Copyright 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-ifneq ($(TARGET_BUILD_PDK),true) # Build MediaComponents only if this is not a PDK build.  MediaComponents won't
-# build in PDK builds because frameworks/base/core/java is not available but
-# IMediaSession2.aidl and IMediaController2.aidl are using classes from
-# frameworks/base/core/java.
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := MediaComponents
-LOCAL_MODULE_OWNER := google
-
-# TODO: create a separate key for this package.
-LOCAL_CERTIFICATE := platform
-
-# TODO: Use System SDK once public APIs are approved
-# LOCAL_SDK_VERSION := system_current
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src) \
-    $(call all-Iaidl-files-under, src)
-
-LOCAL_PROGUARD_FLAG_FILES := proguard.cfg
-
-LOCAL_MULTILIB := first
-
-LOCAL_JAVA_LIBRARIES += androidx.annotation_annotation
-
-# To embed native libraries in package, uncomment the lines below.
-#LOCAL_MODULE_TAGS := samples
-#LOCAL_JNI_SHARED_LIBRARIES := \
-#    libaacextractor \
-#    libamrextractor \
-#    libflacextractor \
-#    libmidiextractor \
-#    libmkvextractor \
-#    libmp3extractor \
-#    libmp4extractor \
-#    libmpeg2extractor \
-#    liboggextractor \
-#    libwavextractor \
-
-# TODO: Remove dependency with other support libraries.
-LOCAL_STATIC_ANDROID_LIBRARIES += \
-    androidx.legacy_legacy-support-v4 \
-    androidx.appcompat_appcompat \
-    androidx.palette_palette
-LOCAL_USE_AAPT2 := true
-
-include $(BUILD_PACKAGE)
-
-endif  # ifneq ($(TARGET_BUILD_PDK),true)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/MediaComponents/AndroidManifest.xml b/packages/MediaComponents/AndroidManifest.xml
deleted file mode 100644
index 50fdca1..0000000
--- a/packages/MediaComponents/AndroidManifest.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.media.update"
-    android:versionCode="1"
-    android:versionName="1.0" >
-
-    <application
-        android:label="Media Components Update"
-        android:multiArch="true"
-        android:allowBackup="false"
-        android:hasCode="false"
-        android:extractNativeLibs="false">
-    </application>
-
-</manifest>
diff --git a/packages/MediaComponents/proguard.cfg b/packages/MediaComponents/proguard.cfg
deleted file mode 100644
index d7bf730..0000000
--- a/packages/MediaComponents/proguard.cfg
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# Copyright 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# Keep entry point for updatable Java classes
--keep public class com.android.media.update.ApiFactory {
-   public static com.android.media.update.ApiFactory initialize(android.content.pm.ApplicationInfo);
-}
diff --git a/packages/MediaComponents/runcts.sh b/packages/MediaComponents/runcts.sh
deleted file mode 100644
index 61b1a1e..0000000
--- a/packages/MediaComponents/runcts.sh
+++ /dev/null
@@ -1,224 +0,0 @@
-#!/bin/bash
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Usage '. runcts.sh'
-
-function _runtest_cts_mediacomponent_usage() {
-  echo 'runtest-cts-MediaComponents [option]: Build, flash device,'
-  echo '              and run subset of CtsMediaTestCases that MediaComponents covers.'
-  echo '          *Warning* This bypasses CTS setup (e.g. download media contents from server)'
-  echo '          For running CTS in official way, use atest or cts-tradefed '
-  echo '     -h|--help: This help'
-  echo '     --skip: Skip build and flash. Just rerun-tests'
-  echo '     --min: Only rebuild tests and updatable library.'
-  echo '     --test: Only rebuild tests'
-  echo '     -s [device_id]: Specify a device name to run test against.'
-  echo '                     You can define ${ADBHOST} instead.'
-  echo '     -r [count]: Repeat tests for given count. It will stop when fails.'
-  echo '     --ignore: Keep repeating tests even when it fails.'
-  echo '     -t [test]: Only run the specific test. Can be either a class or a method.'
-}
-
-function runtest-cts-MediaComponents() {
-  # Edit here if you want to support other tests.
-  # List up libs and apks in the media_api needed for tests, and place test target at the last.
-  local TEST_PACKAGE_DIR=("frameworks/av/packages/MediaComponents/test")
-  local TEST_PACKAGE=("android.media.cts")
-  local BUILD_TARGETS=("MediaComponents" "CtsMediaTestCases")
-  # Don't include MediaComponents -- if we simply install it, system server
-  # wouldn't use the installed one.
-  local INSTALL_TARGETS=("CtsMediaTestCases")
-  local TEST_RUNNER="android.support.test.runner.AndroidJUnitRunner"
-  local DEPENDENCIES=("mockito-target-minus-junit4" "android-support-test" "compatibility-device-util")
-  local DEFAULT_TEST_TARGET=""
-  DEFAULT_TEST_TARGET+="android.media.cts.MediaBrowser2Test"
-  DEFAULT_TEST_TARGET+=",android.media.cts.MediaController2Test"
-  DEFAULT_TEST_TARGET+=",android.media.cts.MediaMetadata2Test"
-  DEFAULT_TEST_TARGET+=",android.media.cts.MediaSession2Test"
-  DEFAULT_TEST_TARGET+=",android.media.cts.MediaSession2_PermissionTest"
-  DEFAULT_TEST_TARGET+=",android.media.cts.MediaSessionManager_MediaSession2Test"
-  DEFAULT_TEST_TARGET+=",android.media.cts.SessionToken2Test"
-  if [[ -z "${ANDROID_BUILD_TOP}" ]]; then
-    echo "Needs to lunch a target first"
-    return
-  fi
-
-  local old_path=${OLDPWD}
-  while true; do
-    local OPTION_SKIP="false"
-    local OPTION_MIN="false"
-    local OPTION_TEST="false"
-    local OPTION_REPEAT_COUNT="1"
-    local OPTION_IGNORE="false"
-    local OPTION_TEST_TARGET="${DEFAULT_TEST_TARGET}"
-    local adbhost_local
-    while (( "$#" )); do
-      case "${1}" in
-        -h|--help)
-          _runtest_cts_mediacomponent_usage
-          return
-          ;;
-        --skip)
-          OPTION_SKIP="true"
-          ;;
-        --min)
-          OPTION_MIN="true"
-          ;;
-        --test)
-          OPTION_TEST="true"
-          ;;
-        -s)
-          shift
-          adbhost_local=${1}
-          ;;
-        -r)
-          shift
-          OPTION_REPEAT_COUNT="${1}"
-          ;;
-        --ignore)
-          OPTION_IGNORE="true"
-          ;;
-        -t)
-          shift
-          OPTION_TEST_TARGET="${1}"
-      esac
-      shift
-    done
-
-    # Build adb command.
-    local adb
-    if [[ -z "${adbhost_local}" ]]; then
-      adbhost_local=${ADBHOST}
-    fi
-    if [[ -z "${adbhost_local}" ]]; then
-      local device_count=$(adb devices | sed '/^[[:space:]]*$/d' | wc -l)
-      if [[ "${device_count}" != "2" ]]; then
-        echo "Too many devices. Specify a device." && break
-      fi
-      adb="adb"
-    else
-      adb="adb -s ${adbhost_local}"
-    fi
-
-    local target_dir="${ANDROID_BUILD_TOP}/${TEST_PACKAGE_DIR}"
-    #local TEST_PACKAGE=$(sed -n 's/^.*\bpackage\b="\([a-z0-9\.]*\)".*$/\1/p' ${target_dir}/AndroidManifest.xml)
-
-    if [[ "${OPTION_SKIP}" != "true" ]]; then
-      # Build dependencies if needed.
-      local dependency
-      local build_dependency=""
-      for dependency in ${DEPENDENCIES[@]}; do
-        if [[ "${dependency}" == "out/"* ]]; then
-          if [[ ! -f ${ANDROID_BUILD_TOP}/${dependency} ]]; then
-            build_dependency="true"
-            break
-          fi
-        else
-          if [[ "$(find ${OUT} -name ${dependency}_intermediates | wc -l)" == "0" ]]; then
-            build_dependency="true"
-            break
-          fi
-        fi
-      done
-      if [[ "${build_dependency}" == "true" ]]; then
-        echo "Building dependencies. Will only print stderr."
-        m ${DEPENDENCIES[@]} -j > /dev/null
-      fi
-
-      # Build test apk and required apk.
-      local build_targets
-      if [[ "${OPTION_TEST}" == "true" ]]; then
-        build_targets="${INSTALL_TARGETS[@]}"
-      elif [[ "${OPTION_MIN}" == "true" ]]; then
-        build_targets="${BUILD_TARGETS[@]}"
-      else
-        build_targets="${BUILD_TARGETS[@]} droid"
-      fi
-      m ${build_targets} -j || break
-
-      if [[ "${OPTION_TEST}" != "true" ]]; then
-        # Flash only when needed
-        local device_build_type="$(${adb} shell getprop ro.build.type)"
-        if [[ "${device_build_type}" == "user" ]]; then
-          # User build. Cannot adb sync
-          ${adb} reboot bootloader
-          fastboot flashall
-        else
-          ${adb} root
-          local device_verity_mode="$(${adb} shell getprop ro.boot.veritymode)"
-          if [[ "${device_verity_mode}" != "disabled" ]]; then
-            ${adb} disable-verity
-            ${adb} reboot
-            ${adb} wait-for-device || break
-            ${adb} root
-          fi
-          ${adb} remount
-          ${adb} shell stop
-          ${adb} shell setprop log.tag.MediaSessionService DEBUG
-          ${adb} sync
-          ${adb} shell start
-        fi
-        ${adb} wait-for-device || break
-        # Ensure package manager is loaded.
-        # TODO(jaewan): Find better way to wait
-        sleep 15
-      fi
-
-      # Install apks
-      local install_failed="false"
-      for target in ${INSTALL_TARGETS[@]}; do
-        local apk_path=$(find ${OUT}/system ${OUT}/data -name ${target}.apk)
-        local apk_num=$(find ${OUT}/system ${OUT}/data -name ${target}.apk | wc -l)
-        if [[ "${apk_num}" != "1" ]]; then
-          echo "Cannot locate a ${target}.apk. Found ${apk_num} apks" && break
-        fi
-        echo "Installing ${target}.apk. path=${apk_path}"
-        ${adb} install -r ${apk_path}
-        if [[ "${?}" != "0" ]]; then
-          install_failed="true"
-          break
-        fi
-      done
-      if [[ "${install_failed}" == "true" ]]; then
-        echo "Failed to install. Test wouldn't run."
-        break
-      fi
-    fi
-
-    local test_target=""
-    if [[ -n "${OPTION_TEST_TARGET}" ]]; then
-      test_target="-e class ${OPTION_TEST_TARGET}"
-    fi
-
-    local i
-    local tmpfile=$(tempfile)
-    for ((i=1; i <= ${OPTION_REPEAT_COUNT}; i++)); do
-      echo "Run test ${i}/${OPTION_REPEAT_COUNT}"
-      ${adb} shell am instrument ${test_target} -w ${TEST_PACKAGE}/${TEST_RUNNER} >& ${tmpfile}
-      cat ${tmpfile}
-      if [[ "${OPTION_IGNORE}" != "true" ]]; then
-        if [[ -n "$(grep ${tmpfile} -e 'FAILURE\|crashed')" ]]; then
-          # am instrument doesn't return error code so need to grep result message instead
-          break
-        fi
-      fi
-    done
-    rm ${tmpfile}
-    break
-  done
-}
-
-echo "Following functions are added to your environment:"
-_runtest_cts_mediacomponent_usage
diff --git a/packages/MediaComponents/src/com/android/media/IMediaController2.aidl b/packages/MediaComponents/src/com/android/media/IMediaController2.aidl
deleted file mode 100644
index cc5acf9..0000000
--- a/packages/MediaComponents/src/com/android/media/IMediaController2.aidl
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media;
-
-import android.app.PendingIntent;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-
-import com.android.media.IMediaSession2;
-
-/**
- * Interface from MediaSession2 to MediaController2.
- * <p>
- * Keep this interface oneway. Otherwise a malicious app may implement fake version of this,
- * and holds calls from session to make session owner(s) frozen.
- */
-// TODO(jaewan): (Post P) Handle when the playlist becomes too huge.
-//               Note that ParcelledSliceList isn't a good idea for the purpose. (see: b/37493677)
-oneway interface IMediaController2 {
-    void onPlayerStateChanged(int state);
-    void onPositionChanged(long eventTimeMs, long positionMs);
-    void onPlaybackSpeedChanged(float speed);
-    void onBufferedPositionChanged(long bufferedPositionMs);
-    void onPlaylistChanged(in List<Bundle> playlist, in Bundle metadata);
-    void onPlaylistMetadataChanged(in Bundle metadata);
-    void onPlaybackInfoChanged(in Bundle playbackInfo);
-    void onRepeatModeChanged(int repeatMode);
-    void onShuffleModeChanged(int shuffleMode);
-    void onError(int errorCode, in Bundle extras);
-
-    void onConnected(IMediaSession2 sessionBinder, in Bundle commandGroup,
-            int playerState, long positionEventTimeMs, long positionMs, float playbackSpeed,
-            long bufferedPositionMs, in Bundle playbackInfo, int repeatMode, int shuffleMode,
-            in List<Bundle> playlist, in PendingIntent sessionActivity);
-    void onDisconnected();
-
-    void onCustomLayoutChanged(in List<Bundle> commandButtonlist);
-    void onAllowedCommandsChanged(in Bundle commands);
-
-    void onCustomCommand(in Bundle command, in Bundle args, in ResultReceiver receiver);
-}
diff --git a/packages/MediaComponents/src/com/android/media/IMediaSession2.aidl b/packages/MediaComponents/src/com/android/media/IMediaSession2.aidl
deleted file mode 100644
index 5761455..0000000
--- a/packages/MediaComponents/src/com/android/media/IMediaSession2.aidl
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media;
-
-import android.os.Bundle;
-import android.os.ResultReceiver;
-import android.net.Uri;
-
-import com.android.media.IMediaController2;
-
-/**
- * Interface from MediaController2 to MediaSession2.
- * <p>
- * Keep this interface oneway. Otherwise a malicious app may implement fake version of this,
- * and holds calls from session to make session owner(s) frozen.
- */
- // TODO(jaewan): (Post P) Handle when the playlist becomes too huge.
- //               Note that ParcelledSliceList isn't a good idea for the purpose. (see: b/37493677)
-oneway interface IMediaSession2 {
-    // TODO(jaewan): add onCommand() to send private command
-
-    // TODO(jaewan): (Post P) We may consider to add another binder just for the connection
-    //               not to expose other methods to the controller whose connection wasn't accepted.
-    //               But this would be enough for now because it's the same as existing
-    //               MediaBrowser and MediaBrowserService.
-    void connect(IMediaController2 caller, String callingPackage);
-    void release(IMediaController2 caller);
-
-    void setVolumeTo(IMediaController2 caller, int value, int flags);
-    void adjustVolume(IMediaController2 caller, int direction, int flags);
-
-    //////////////////////////////////////////////////////////////////////////////////////////////
-    // send command
-    //////////////////////////////////////////////////////////////////////////////////////////////
-    void sendTransportControlCommand(IMediaController2 caller,
-            int commandCode, in Bundle args);
-    void sendCustomCommand(IMediaController2 caller, in Bundle command, in Bundle args,
-            in ResultReceiver receiver);
-
-    void prepareFromUri(IMediaController2 caller, in Uri uri, in Bundle extras);
-    void prepareFromSearch(IMediaController2 caller, String query, in Bundle extras);
-    void prepareFromMediaId(IMediaController2 caller, String mediaId, in Bundle extras);
-    void playFromUri(IMediaController2 caller, in Uri uri, in Bundle extras);
-    void playFromSearch(IMediaController2 caller, String query, in Bundle extras);
-    void playFromMediaId(IMediaController2 caller, String mediaId, in Bundle extras);
-    void setRating(IMediaController2 caller, String mediaId, in Bundle rating);
-
-    void setPlaylist(IMediaController2 caller, in List<Bundle> playlist, in Bundle metadata);
-    void updatePlaylistMetadata(IMediaController2 caller, in Bundle metadata);
-    void addPlaylistItem(IMediaController2 caller, int index, in Bundle mediaItem);
-    void removePlaylistItem(IMediaController2 caller, in Bundle mediaItem);
-    void replacePlaylistItem(IMediaController2 caller, int index, in Bundle mediaItem);
-    void skipToPlaylistItem(IMediaController2 caller, in Bundle mediaItem);
-    void skipToPreviousItem(IMediaController2 caller);
-    void skipToNextItem(IMediaController2 caller);
-    void setRepeatMode(IMediaController2 caller, int repeatMode);
-    void setShuffleMode(IMediaController2 caller, int shuffleMode);
-}
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
deleted file mode 100644
index 1c4cf82..0000000
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ /dev/null
@@ -1,1085 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media;
-
-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 static android.media.SessionCommand2.COMMAND_CODE_SET_VOLUME;
-
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.media.AudioAttributes;
-import android.media.MediaController2;
-import android.media.MediaController2.ControllerCallback;
-import android.media.MediaController2.PlaybackInfo;
-import android.media.MediaItem2;
-import android.media.MediaMetadata2;
-import android.media.MediaPlaylistAgent.RepeatMode;
-import android.media.MediaPlaylistAgent.ShuffleMode;
-import android.media.MediaSession2.CommandButton;
-import android.media.Rating2;
-import android.media.SessionCommand2;
-import android.media.SessionCommandGroup2;
-import android.media.SessionToken2;
-import android.media.update.MediaController2Provider;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.UserHandle;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.annotation.GuardedBy;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-public class MediaController2Impl implements MediaController2Provider {
-    private static final String TAG = "MediaController2";
-    private static final boolean DEBUG = true; // TODO(jaewan): Change
-
-    private final MediaController2 mInstance;
-    private final Context mContext;
-    private final Object mLock = new Object();
-
-    private final MediaController2Stub mControllerStub;
-    private final SessionToken2 mToken;
-    private final ControllerCallback mCallback;
-    private final Executor mCallbackExecutor;
-    private final IBinder.DeathRecipient mDeathRecipient;
-
-    @GuardedBy("mLock")
-    private SessionServiceConnection mServiceConnection;
-    @GuardedBy("mLock")
-    private boolean mIsReleased;
-    @GuardedBy("mLock")
-    private List<MediaItem2> mPlaylist;
-    @GuardedBy("mLock")
-    private MediaMetadata2 mPlaylistMetadata;
-    @GuardedBy("mLock")
-    private @RepeatMode int mRepeatMode;
-    @GuardedBy("mLock")
-    private @ShuffleMode int mShuffleMode;
-    @GuardedBy("mLock")
-    private int mPlayerState;
-    @GuardedBy("mLock")
-    private long mPositionEventTimeMs;
-    @GuardedBy("mLock")
-    private long mPositionMs;
-    @GuardedBy("mLock")
-    private float mPlaybackSpeed;
-    @GuardedBy("mLock")
-    private long mBufferedPositionMs;
-    @GuardedBy("mLock")
-    private PlaybackInfo mPlaybackInfo;
-    @GuardedBy("mLock")
-    private PendingIntent mSessionActivity;
-    @GuardedBy("mLock")
-    private SessionCommandGroup2 mAllowedCommands;
-
-    // Assignment should be used with the lock hold, but should be used without a lock to prevent
-    // potential deadlock.
-    // Postfix -Binder is added to explicitly show that it's potentially remote process call.
-    // Technically -Interface is more correct, but it may misread that it's interface (vs class)
-    // so let's keep this postfix until we find better postfix.
-    @GuardedBy("mLock")
-    private volatile IMediaSession2 mSessionBinder;
-
-    // TODO(jaewan): Require session activeness changed listener, because controller can be
-    //               available when the session's player is null.
-    public MediaController2Impl(Context context, MediaController2 instance, SessionToken2 token,
-            Executor executor, ControllerCallback callback) {
-        mInstance = instance;
-        if (context == null) {
-            throw new IllegalArgumentException("context shouldn't be null");
-        }
-        if (token == null) {
-            throw new IllegalArgumentException("token shouldn't be null");
-        }
-        if (callback == null) {
-            throw new IllegalArgumentException("callback shouldn't be null");
-        }
-        if (executor == null) {
-            throw new IllegalArgumentException("executor shouldn't be null");
-        }
-        mContext = context;
-        mControllerStub = new MediaController2Stub(this);
-        mToken = token;
-        mCallback = callback;
-        mCallbackExecutor = executor;
-        mDeathRecipient = () -> {
-            mInstance.close();
-        };
-
-        mSessionBinder = null;
-    }
-
-    @Override
-    public void initialize() {
-        // TODO(jaewan): More sanity checks.
-        if (mToken.getType() == SessionToken2.TYPE_SESSION) {
-            // Session
-            mServiceConnection = null;
-            connectToSession(SessionToken2Impl.from(mToken).getSessionBinder());
-        }
-    }
-
-    private void connectToSession(IMediaSession2 sessionBinder) {
-        try {
-            sessionBinder.connect(mControllerStub, mContext.getPackageName());
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed to call connection request. Framework will retry"
-                    + " automatically");
-        }
-    }
-
-    @Override
-    public void close_impl() {
-        if (DEBUG) {
-            Log.d(TAG, "release from " + mToken);
-        }
-        final IMediaSession2 binder;
-        synchronized (mLock) {
-            if (mIsReleased) {
-                // Prevent re-enterance from the ControllerCallback.onDisconnected()
-                return;
-            }
-            mIsReleased = true;
-            if (mServiceConnection != null) {
-                mContext.unbindService(mServiceConnection);
-                mServiceConnection = null;
-            }
-            binder = mSessionBinder;
-            mSessionBinder = null;
-            mControllerStub.destroy();
-        }
-        if (binder != null) {
-            try {
-                binder.asBinder().unlinkToDeath(mDeathRecipient, 0);
-                binder.release(mControllerStub);
-            } catch (RemoteException e) {
-                // No-op.
-            }
-        }
-        mCallbackExecutor.execute(() -> {
-            mCallback.onDisconnected(mInstance);
-        });
-    }
-
-    IMediaSession2 getSessionBinder() {
-        return mSessionBinder;
-    }
-
-    MediaController2Stub getControllerStub() {
-        return mControllerStub;
-    }
-
-    Executor getCallbackExecutor() {
-        return mCallbackExecutor;
-    }
-
-    Context getContext() {
-        return mContext;
-    }
-
-    MediaController2 getInstance() {
-        return mInstance;
-    }
-
-    // Returns session binder if the controller can send the command.
-    IMediaSession2 getSessionBinderIfAble(int commandCode) {
-        synchronized (mLock) {
-            if (!mAllowedCommands.hasCommand(commandCode)) {
-                // Cannot send because isn't allowed to.
-                Log.w(TAG, "Controller isn't allowed to call command, commandCode="
-                        + commandCode);
-                return null;
-            }
-        }
-        // TODO(jaewan): Should we do this with the lock hold?
-        final IMediaSession2 binder = mSessionBinder;
-        if (binder == null) {
-            // Cannot send because disconnected.
-            Log.w(TAG, "Session is disconnected");
-        }
-        return binder;
-    }
-
-    // Returns session binder if the controller can send the command.
-    IMediaSession2 getSessionBinderIfAble(SessionCommand2 command) {
-        synchronized (mLock) {
-            if (!mAllowedCommands.hasCommand(command)) {
-                Log.w(TAG, "Controller isn't allowed to call command, command=" + command);
-                return null;
-            }
-        }
-        // TODO(jaewan): Should we do this with the lock hold?
-        final IMediaSession2 binder = mSessionBinder;
-        if (binder == null) {
-            // Cannot send because disconnected.
-            Log.w(TAG, "Session is disconnected");
-        }
-        return binder;
-    }
-
-    @Override
-    public SessionToken2 getSessionToken_impl() {
-        return mToken;
-    }
-
-    @Override
-    public boolean isConnected_impl() {
-        final IMediaSession2 binder = mSessionBinder;
-        return binder != null;
-    }
-
-    @Override
-    public void play_impl() {
-        sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY);
-    }
-
-    @Override
-    public void pause_impl() {
-        sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE);
-    }
-
-    @Override
-    public void stop_impl() {
-        sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_STOP);
-    }
-
-    @Override
-    public void skipToPlaylistItem_impl(MediaItem2 item) {
-        if (item == null) {
-            throw new IllegalArgumentException("item shouldn't be null");
-        }
-        final IMediaSession2 binder = mSessionBinder;
-        if (binder != null) {
-            try {
-                binder.skipToPlaylistItem(mControllerStub, item.toBundle());
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            Log.w(TAG, "Session isn't active", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void skipToPreviousItem_impl() {
-        final IMediaSession2 binder = mSessionBinder;
-        if (binder != null) {
-            try {
-                binder.skipToPreviousItem(mControllerStub);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            Log.w(TAG, "Session isn't active", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void skipToNextItem_impl() {
-        final IMediaSession2 binder = mSessionBinder;
-        if (binder != null) {
-            try {
-                binder.skipToNextItem(mControllerStub);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            Log.w(TAG, "Session isn't active", new IllegalStateException());
-        }
-    }
-
-    private void sendTransportControlCommand(int commandCode) {
-        sendTransportControlCommand(commandCode, null);
-    }
-
-    private void sendTransportControlCommand(int commandCode, Bundle args) {
-        final IMediaSession2 binder = mSessionBinder;
-        if (binder != null) {
-            try {
-                binder.sendTransportControlCommand(mControllerStub, commandCode, args);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            Log.w(TAG, "Session isn't active", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public PendingIntent getSessionActivity_impl() {
-        return mSessionActivity;
-    }
-
-    @Override
-    public void setVolumeTo_impl(int value, int flags) {
-        // TODO(hdmoon): sanity check
-        final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SET_VOLUME);
-        if (binder != null) {
-            try {
-                binder.setVolumeTo(mControllerStub, value, flags);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            Log.w(TAG, "Session isn't active", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void adjustVolume_impl(int direction, int flags) {
-        // TODO(hdmoon): sanity check
-        final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SET_VOLUME);
-        if (binder != null) {
-            try {
-                binder.adjustVolume(mControllerStub, direction, flags);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            Log.w(TAG, "Session isn't active", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void prepareFromUri_impl(Uri uri, Bundle extras) {
-        final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SESSION_PREPARE_FROM_URI);
-        if (uri == null) {
-            throw new IllegalArgumentException("uri shouldn't be null");
-        }
-        if (binder != null) {
-            try {
-                binder.prepareFromUri(mControllerStub, uri, extras);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            // TODO(jaewan): Handle.
-        }
-    }
-
-    @Override
-    public void prepareFromSearch_impl(String query, Bundle extras) {
-        final IMediaSession2 binder = getSessionBinderIfAble(
-                COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH);
-        if (TextUtils.isEmpty(query)) {
-            throw new IllegalArgumentException("query shouldn't be empty");
-        }
-        if (binder != null) {
-            try {
-                binder.prepareFromSearch(mControllerStub, query, extras);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            // TODO(jaewan): Handle.
-        }
-    }
-
-    @Override
-    public void prepareFromMediaId_impl(String mediaId, Bundle extras) {
-        final IMediaSession2 binder = getSessionBinderIfAble(
-                COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID);
-        if (mediaId == null) {
-            throw new IllegalArgumentException("mediaId shouldn't be null");
-        }
-        if (binder != null) {
-            try {
-                binder.prepareFromMediaId(mControllerStub, mediaId, extras);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            // TODO(jaewan): Handle.
-        }
-    }
-
-    @Override
-    public void playFromUri_impl(Uri uri, Bundle extras) {
-        final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SESSION_PLAY_FROM_URI);
-        if (uri == null) {
-            throw new IllegalArgumentException("uri shouldn't be null");
-        }
-        if (binder != null) {
-            try {
-                binder.playFromUri(mControllerStub, uri, extras);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            // TODO(jaewan): Handle.
-        }
-    }
-
-    @Override
-    public void playFromSearch_impl(String query, Bundle extras) {
-        final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SESSION_PLAY_FROM_SEARCH);
-        if (TextUtils.isEmpty(query)) {
-            throw new IllegalArgumentException("query shouldn't be empty");
-        }
-        if (binder != null) {
-            try {
-                binder.playFromSearch(mControllerStub, query, extras);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            // TODO(jaewan): Handle.
-        }
-    }
-
-    @Override
-    public void playFromMediaId_impl(String mediaId, Bundle extras) {
-        final IMediaSession2 binder = getSessionBinderIfAble(
-                COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID);
-        if (mediaId == null) {
-            throw new IllegalArgumentException("mediaId shouldn't be null");
-        }
-        if (binder != null) {
-            try {
-                binder.playFromMediaId(mControllerStub, mediaId, extras);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            // TODO(jaewan): Handle.
-        }
-    }
-
-    @Override
-    public void setRating_impl(String mediaId, Rating2 rating) {
-        if (mediaId == null) {
-            throw new IllegalArgumentException("mediaId shouldn't be null");
-        }
-        if (rating == null) {
-            throw new IllegalArgumentException("rating shouldn't be null");
-        }
-
-        final IMediaSession2 binder = mSessionBinder;
-        if (binder != null) {
-            try {
-                binder.setRating(mControllerStub, mediaId, rating.toBundle());
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            // TODO(jaewan): Handle.
-        }
-    }
-
-    @Override
-    public void sendCustomCommand_impl(SessionCommand2 command, Bundle args, ResultReceiver cb) {
-        if (command == null) {
-            throw new IllegalArgumentException("command shouldn't be null");
-        }
-        final IMediaSession2 binder = getSessionBinderIfAble(command);
-        if (binder != null) {
-            try {
-                binder.sendCustomCommand(mControllerStub, command.toBundle(), args, cb);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            Log.w(TAG, "Session isn't active", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public List<MediaItem2> getPlaylist_impl() {
-        synchronized (mLock) {
-            return mPlaylist;
-        }
-    }
-
-    @Override
-    public void setPlaylist_impl(List<MediaItem2> list, MediaMetadata2 metadata) {
-        if (list == null) {
-            throw new IllegalArgumentException("list shouldn't be null");
-        }
-        final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_SET_LIST);
-        if (binder != null) {
-            List<Bundle> bundleList = new ArrayList<>();
-            for (int i = 0; i < list.size(); i++) {
-                bundleList.add(list.get(i).toBundle());
-            }
-            Bundle metadataBundle = (metadata == null) ? null : metadata.toBundle();
-            try {
-                binder.setPlaylist(mControllerStub, bundleList, metadataBundle);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            Log.w(TAG, "Session isn't active", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public MediaMetadata2 getPlaylistMetadata_impl() {
-        synchronized (mLock) {
-            return mPlaylistMetadata;
-        }
-    }
-
-    @Override
-    public void updatePlaylistMetadata_impl(MediaMetadata2 metadata) {
-        final IMediaSession2 binder = getSessionBinderIfAble(
-                COMMAND_CODE_PLAYLIST_SET_LIST_METADATA);
-        if (binder != null) {
-            Bundle metadataBundle = (metadata == null) ? null : metadata.toBundle();
-            try {
-                binder.updatePlaylistMetadata(mControllerStub, metadataBundle);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            Log.w(TAG, "Session isn't active", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void prepare_impl() {
-        sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_PREPARE);
-    }
-
-    @Override
-    public void fastForward_impl() {
-        // 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() {
-        // TODO(jaewan): Implement this. Note that rewind isn't a transport command anymore
-        //sendTransportControlCommand(MediaSession2.COMMAND_CODE_SESSION_REWIND);
-    }
-
-    @Override
-    public void seekTo_impl(long pos) {
-        if (pos < 0) {
-            throw new IllegalArgumentException("position shouldn't be negative");
-        }
-        Bundle args = new Bundle();
-        args.putLong(MediaSession2Stub.ARGUMENT_KEY_POSITION, pos);
-        sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_SEEK_TO, args);
-    }
-
-    @Override
-    public void addPlaylistItem_impl(int index, MediaItem2 item) {
-        if (index < 0) {
-            throw new IllegalArgumentException("index shouldn't be negative");
-        }
-        if (item == null) {
-            throw new IllegalArgumentException("item shouldn't be null");
-        }
-        final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_ADD_ITEM);
-        if (binder != null) {
-            try {
-                binder.addPlaylistItem(mControllerStub, index, item.toBundle());
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            Log.w(TAG, "Session isn't active", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void removePlaylistItem_impl(MediaItem2 item) {
-        if (item == null) {
-            throw new IllegalArgumentException("item shouldn't be null");
-        }
-        final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_REMOVE_ITEM);
-        if (binder != null) {
-            try {
-                binder.removePlaylistItem(mControllerStub, item.toBundle());
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            Log.w(TAG, "Session isn't active", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void replacePlaylistItem_impl(int index, MediaItem2 item) {
-        if (index < 0) {
-            throw new IllegalArgumentException("index shouldn't be negative");
-        }
-        if (item == null) {
-            throw new IllegalArgumentException("item shouldn't be null");
-        }
-        final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_REPLACE_ITEM);
-        if (binder != null) {
-            try {
-                binder.replacePlaylistItem(mControllerStub, index, item.toBundle());
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            Log.w(TAG, "Session isn't active", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public int getShuffleMode_impl() {
-        return mShuffleMode;
-    }
-
-    @Override
-    public void setShuffleMode_impl(int shuffleMode) {
-        final IMediaSession2 binder = getSessionBinderIfAble(
-                COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE);
-        if (binder != null) {
-            try {
-                binder.setShuffleMode(mControllerStub, shuffleMode);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            Log.w(TAG, "Session isn't active", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public int getRepeatMode_impl() {
-        return mRepeatMode;
-    }
-
-    @Override
-    public void setRepeatMode_impl(int repeatMode) {
-        final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE);
-        if (binder != null) {
-            try {
-                binder.setRepeatMode(mControllerStub, repeatMode);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            Log.w(TAG, "Session isn't active", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public PlaybackInfo getPlaybackInfo_impl() {
-        synchronized (mLock) {
-            return mPlaybackInfo;
-        }
-    }
-
-    @Override
-    public int getPlayerState_impl() {
-        synchronized (mLock) {
-            return mPlayerState;
-        }
-    }
-
-    @Override
-    public long getCurrentPosition_impl() {
-        synchronized (mLock) {
-            long timeDiff = System.currentTimeMillis() - mPositionEventTimeMs;
-            long expectedPosition = mPositionMs + (long) (mPlaybackSpeed * timeDiff);
-            return Math.max(0, expectedPosition);
-        }
-    }
-
-    @Override
-    public float getPlaybackSpeed_impl() {
-        synchronized (mLock) {
-            return mPlaybackSpeed;
-        }
-    }
-
-    @Override
-    public long getBufferedPosition_impl() {
-        synchronized (mLock) {
-            return mBufferedPositionMs;
-        }
-    }
-
-    @Override
-    public MediaItem2 getCurrentMediaItem_impl() {
-        // TODO(jaewan): Implement
-        return null;
-    }
-
-    void pushPlayerStateChanges(final int state) {
-        synchronized (mLock) {
-            mPlayerState = state;
-        }
-        mCallbackExecutor.execute(() -> {
-            if (!mInstance.isConnected()) {
-                return;
-            }
-            mCallback.onPlayerStateChanged(mInstance, state);
-        });
-    }
-
-    // TODO(jaewan): Rename to seek completed
-    void pushPositionChanges(final long eventTimeMs, final long positionMs) {
-        synchronized (mLock) {
-            mPositionEventTimeMs = eventTimeMs;
-            mPositionMs = positionMs;
-        }
-        mCallbackExecutor.execute(() -> {
-            if (!mInstance.isConnected()) {
-                return;
-            }
-            mCallback.onSeekCompleted(mInstance, positionMs);
-        });
-    }
-
-    void pushPlaybackSpeedChanges(final float speed) {
-        synchronized (mLock) {
-            mPlaybackSpeed = speed;
-        }
-        mCallbackExecutor.execute(() -> {
-            if (!mInstance.isConnected()) {
-                return;
-            }
-            mCallback.onPlaybackSpeedChanged(mInstance, speed);
-        });
-    }
-
-    void pushBufferedPositionChanges(final long bufferedPositionMs) {
-        synchronized (mLock) {
-            mBufferedPositionMs = bufferedPositionMs;
-        }
-        mCallbackExecutor.execute(() -> {
-            if (!mInstance.isConnected()) {
-                return;
-            }
-            // TODO(jaewan): Fix this -- it's now buffered state
-            //mCallback.onBufferedPositionChanged(mInstance, bufferedPositionMs);
-        });
-    }
-
-    void pushPlaybackInfoChanges(final PlaybackInfo info) {
-        synchronized (mLock) {
-            mPlaybackInfo = info;
-        }
-        mCallbackExecutor.execute(() -> {
-            if (!mInstance.isConnected()) {
-                return;
-            }
-            mCallback.onPlaybackInfoChanged(mInstance, info);
-        });
-    }
-
-    void pushPlaylistChanges(final List<MediaItem2> playlist, final MediaMetadata2 metadata) {
-        synchronized (mLock) {
-            mPlaylist = playlist;
-            mPlaylistMetadata = metadata;
-        }
-        mCallbackExecutor.execute(() -> {
-            if (!mInstance.isConnected()) {
-                return;
-            }
-            mCallback.onPlaylistChanged(mInstance, playlist, metadata);
-        });
-    }
-
-    void pushPlaylistMetadataChanges(MediaMetadata2 metadata) {
-        synchronized (mLock) {
-            mPlaylistMetadata = metadata;
-        }
-        mCallbackExecutor.execute(() -> {
-            if (!mInstance.isConnected()) {
-                return;
-            }
-            mCallback.onPlaylistMetadataChanged(mInstance, metadata);
-        });
-    }
-
-    void pushShuffleModeChanges(int shuffleMode) {
-        synchronized (mLock) {
-            mShuffleMode = shuffleMode;
-        }
-        mCallbackExecutor.execute(() -> {
-            if (!mInstance.isConnected()) {
-                return;
-            }
-            mCallback.onShuffleModeChanged(mInstance, shuffleMode);
-        });
-    }
-
-    void pushRepeatModeChanges(int repeatMode) {
-        synchronized (mLock) {
-            mRepeatMode = repeatMode;
-        }
-        mCallbackExecutor.execute(() -> {
-            if (!mInstance.isConnected()) {
-                return;
-            }
-            mCallback.onRepeatModeChanged(mInstance, repeatMode);
-        });
-    }
-
-    void pushError(int errorCode, Bundle extras) {
-        mCallbackExecutor.execute(() -> {
-            if (!mInstance.isConnected()) {
-                return;
-            }
-            mCallback.onError(mInstance, errorCode, extras);
-        });
-    }
-
-    // Should be used without a lock to prevent potential deadlock.
-    void onConnectedNotLocked(IMediaSession2 sessionBinder,
-            final SessionCommandGroup2 allowedCommands,
-            final int playerState,
-            final long positionEventTimeMs,
-            final long positionMs,
-            final float playbackSpeed,
-            final long bufferedPositionMs,
-            final PlaybackInfo info,
-            final int repeatMode,
-            final int shuffleMode,
-            final List<MediaItem2> playlist,
-            final PendingIntent sessionActivity) {
-        if (DEBUG) {
-            Log.d(TAG, "onConnectedNotLocked sessionBinder=" + sessionBinder
-                    + ", allowedCommands=" + allowedCommands);
-        }
-        boolean close = false;
-        try {
-            if (sessionBinder == null || allowedCommands == null) {
-                // Connection rejected.
-                close = true;
-                return;
-            }
-            synchronized (mLock) {
-                if (mIsReleased) {
-                    return;
-                }
-                if (mSessionBinder != null) {
-                    Log.e(TAG, "Cannot be notified about the connection result many times."
-                            + " Probably a bug or malicious app.");
-                    close = true;
-                    return;
-                }
-                mAllowedCommands = allowedCommands;
-                mPlayerState = playerState;
-                mPositionEventTimeMs = positionEventTimeMs;
-                mPositionMs = positionMs;
-                mPlaybackSpeed = playbackSpeed;
-                mBufferedPositionMs = bufferedPositionMs;
-                mPlaybackInfo = info;
-                mRepeatMode = repeatMode;
-                mShuffleMode = shuffleMode;
-                mPlaylist = playlist;
-                mSessionActivity = sessionActivity;
-                mSessionBinder = sessionBinder;
-                try {
-                    // Implementation for the local binder is no-op,
-                    // so can be used without worrying about deadlock.
-                    mSessionBinder.asBinder().linkToDeath(mDeathRecipient, 0);
-                } catch (RemoteException e) {
-                    if (DEBUG) {
-                        Log.d(TAG, "Session died too early.", e);
-                    }
-                    close = true;
-                    return;
-                }
-            }
-            // TODO(jaewan): Keep commands to prevents illegal API calls.
-            mCallbackExecutor.execute(() -> {
-                // Note: We may trigger ControllerCallbacks with the initial values
-                // But it's hard to define the order of the controller callbacks
-                // Only notify about the
-                mCallback.onConnected(mInstance, allowedCommands);
-            });
-        } finally {
-            if (close) {
-                // Trick to call release() without holding the lock, to prevent potential deadlock
-                // with the developer's custom lock within the ControllerCallback.onDisconnected().
-                mInstance.close();
-            }
-        }
-    }
-
-    void onCustomCommand(final SessionCommand2 command, final Bundle args,
-            final ResultReceiver receiver) {
-        if (DEBUG) {
-            Log.d(TAG, "onCustomCommand cmd=" + command);
-        }
-        mCallbackExecutor.execute(() -> {
-            // TODO(jaewan): Double check if the controller exists.
-            mCallback.onCustomCommand(mInstance, command, args, receiver);
-        });
-    }
-
-    void onAllowedCommandsChanged(final SessionCommandGroup2 commands) {
-        mCallbackExecutor.execute(() -> {
-            mCallback.onAllowedCommandsChanged(mInstance, commands);
-        });
-    }
-
-    void onCustomLayoutChanged(final List<CommandButton> layout) {
-        mCallbackExecutor.execute(() -> {
-            mCallback.onCustomLayoutChanged(mInstance, layout);
-        });
-    }
-
-    // This will be called on the main thread.
-    private class SessionServiceConnection implements ServiceConnection {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            // Note that it's always main-thread.
-            if (DEBUG) {
-                Log.d(TAG, "onServiceConnected " + name + " " + this);
-            }
-            // Sanity check
-            if (!mToken.getPackageName().equals(name.getPackageName())) {
-                Log.wtf(TAG, name + " was connected, but expected pkg="
-                        + mToken.getPackageName() + " with id=" + mToken.getId());
-                return;
-            }
-            final IMediaSession2 sessionBinder = IMediaSession2.Stub.asInterface(service);
-            connectToSession(sessionBinder);
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            // Temporal lose of the binding because of the service crash. System will automatically
-            // rebind, so just no-op.
-            // TODO(jaewan): Really? Either disconnect cleanly or
-            if (DEBUG) {
-                Log.w(TAG, "Session service " + name + " is disconnected.");
-            }
-        }
-
-        @Override
-        public void onBindingDied(ComponentName name) {
-            // Permanent lose of the binding because of the service package update or removed.
-            // This SessionServiceRecord will be removed accordingly, but forget session binder here
-            // for sure.
-            mInstance.close();
-        }
-    }
-
-    public static final class PlaybackInfoImpl implements PlaybackInfoProvider {
-
-        private static final String KEY_PLAYBACK_TYPE =
-                "android.media.playbackinfo_impl.playback_type";
-        private static final String KEY_CONTROL_TYPE =
-                "android.media.playbackinfo_impl.control_type";
-        private static final String KEY_MAX_VOLUME =
-                "android.media.playbackinfo_impl.max_volume";
-        private static final String KEY_CURRENT_VOLUME =
-                "android.media.playbackinfo_impl.current_volume";
-        private static final String KEY_AUDIO_ATTRIBUTES =
-                "android.media.playbackinfo_impl.audio_attrs";
-
-        private final PlaybackInfo mInstance;
-
-        private final int mPlaybackType;
-        private final int mControlType;
-        private final int mMaxVolume;
-        private final int mCurrentVolume;
-        private final AudioAttributes mAudioAttrs;
-
-        private PlaybackInfoImpl(int playbackType, AudioAttributes attrs, int controlType,
-                int max, int current) {
-            mPlaybackType = playbackType;
-            mAudioAttrs = attrs;
-            mControlType = controlType;
-            mMaxVolume = max;
-            mCurrentVolume = current;
-            mInstance = new PlaybackInfo(this);
-        }
-
-        @Override
-        public int getPlaybackType_impl() {
-            return mPlaybackType;
-        }
-
-        @Override
-        public AudioAttributes getAudioAttributes_impl() {
-            return mAudioAttrs;
-        }
-
-        @Override
-        public int getControlType_impl() {
-            return mControlType;
-        }
-
-        @Override
-        public int getMaxVolume_impl() {
-            return mMaxVolume;
-        }
-
-        @Override
-        public int getCurrentVolume_impl() {
-            return mCurrentVolume;
-        }
-
-        PlaybackInfo getInstance() {
-            return mInstance;
-        }
-
-        Bundle toBundle() {
-            Bundle bundle = new Bundle();
-            bundle.putInt(KEY_PLAYBACK_TYPE, mPlaybackType);
-            bundle.putInt(KEY_CONTROL_TYPE, mControlType);
-            bundle.putInt(KEY_MAX_VOLUME, mMaxVolume);
-            bundle.putInt(KEY_CURRENT_VOLUME, mCurrentVolume);
-            bundle.putParcelable(KEY_AUDIO_ATTRIBUTES, mAudioAttrs);
-            return bundle;
-        }
-
-        static PlaybackInfo createPlaybackInfo(int playbackType, AudioAttributes attrs,
-                int controlType, int max, int current) {
-            return new PlaybackInfoImpl(playbackType, attrs, controlType, max, current)
-                    .getInstance();
-        }
-
-        static PlaybackInfo fromBundle(Bundle bundle) {
-            if (bundle == null) {
-                return null;
-            }
-            final int volumeType = bundle.getInt(KEY_PLAYBACK_TYPE);
-            final int volumeControl = bundle.getInt(KEY_CONTROL_TYPE);
-            final int maxVolume = bundle.getInt(KEY_MAX_VOLUME);
-            final int currentVolume = bundle.getInt(KEY_CURRENT_VOLUME);
-            final AudioAttributes attrs = bundle.getParcelable(KEY_AUDIO_ATTRIBUTES);
-
-            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
deleted file mode 100644
index 5b71e65..0000000
--- a/packages/MediaComponents/src/com/android/media/MediaController2Stub.java
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.media.MediaController2;
-import android.media.MediaItem2;
-import android.media.MediaMetadata2;
-import android.media.MediaSession2.CommandButton;
-import android.media.SessionCommand2;
-import android.media.SessionCommandGroup2;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.media.MediaController2Impl.PlaybackInfoImpl;
-import com.android.media.MediaSession2Impl.CommandButtonImpl;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-
-public class MediaController2Stub extends IMediaController2.Stub {
-    private static final String TAG = "MediaController2Stub";
-    private static final boolean DEBUG = true; // TODO(jaewan): Change
-
-    private final WeakReference<MediaController2Impl> mController;
-
-    MediaController2Stub(MediaController2Impl controller) {
-        mController = new WeakReference<>(controller);
-    }
-
-    private MediaController2Impl getController() throws IllegalStateException {
-        final MediaController2Impl controller = mController.get();
-        if (controller == null) {
-            throw new IllegalStateException("Controller is released");
-        }
-        return controller;
-    }
-
-    public void destroy() {
-        mController.clear();
-    }
-
-    @Override
-    public void onPlayerStateChanged(int state) {
-        final MediaController2Impl controller;
-        try {
-            controller = getController();
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-            return;
-        }
-        controller.pushPlayerStateChanges(state);
-    }
-
-    @Override
-    public void onPositionChanged(long eventTimeMs, long positionMs) {
-        final MediaController2Impl controller;
-        try {
-            controller = getController();
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-            return;
-        }
-        if (eventTimeMs < 0) {
-            Log.w(TAG, "onPositionChanged(): Ignoring negative eventTimeMs");
-            return;
-        }
-        if (positionMs < 0) {
-            Log.w(TAG, "onPositionChanged(): Ignoring negative positionMs");
-            return;
-        }
-        controller.pushPositionChanges(eventTimeMs, positionMs);
-    }
-
-    @Override
-    public void onPlaybackSpeedChanged(float speed) {
-        final MediaController2Impl controller;
-        try {
-            controller = getController();
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-            return;
-        }
-        controller.pushPlaybackSpeedChanges(speed);
-    }
-
-    @Override
-    public void onBufferedPositionChanged(long bufferedPositionMs) {
-        final MediaController2Impl controller;
-        try {
-            controller = getController();
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-            return;
-        }
-        if (bufferedPositionMs < 0) {
-            Log.w(TAG, "onBufferedPositionChanged(): Ignoring negative bufferedPositionMs");
-            return;
-        }
-        controller.pushBufferedPositionChanges(bufferedPositionMs);
-    }
-
-    @Override
-    public void onPlaylistChanged(List<Bundle> playlistBundle, Bundle metadataBundle) {
-        final MediaController2Impl controller;
-        try {
-            controller = getController();
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-            return;
-        }
-        if (playlistBundle == null) {
-            Log.w(TAG, "onPlaylistChanged(): Ignoring null playlist from " + controller);
-            return;
-        }
-        List<MediaItem2> playlist = new ArrayList<>();
-        for (Bundle bundle : playlistBundle) {
-            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(metadataBundle);
-        controller.pushPlaylistChanges(playlist, metadata);
-    }
-
-    @Override
-    public void onPlaylistMetadataChanged(Bundle metadataBundle) throws RuntimeException {
-        final MediaController2Impl controller;
-        try {
-            controller = getController();
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-            return;
-        }
-        MediaMetadata2 metadata = MediaMetadata2.fromBundle(metadataBundle);
-        controller.pushPlaylistMetadataChanges(metadata);
-    }
-
-    @Override
-    public void onRepeatModeChanged(int repeatMode) {
-        final MediaController2Impl controller;
-        try {
-            controller = getController();
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-            return;
-        }
-        controller.pushRepeatModeChanges(repeatMode);
-    }
-
-    @Override
-    public void onPlaybackInfoChanged(Bundle playbackInfo) throws RuntimeException {
-        if (DEBUG) {
-            Log.d(TAG, "onPlaybackInfoChanged");
-        }
-        final MediaController2Impl controller;
-        try {
-            controller = getController();
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-            return;
-        }
-        MediaController2.PlaybackInfo info = PlaybackInfoImpl.fromBundle(playbackInfo);
-        if (info == null) {
-            Log.w(TAG, "onPlaybackInfoChanged(): Ignoring null playbackInfo");
-            return;
-        }
-        controller.pushPlaybackInfoChanges(info);
-    }
-
-    @Override
-    public void onShuffleModeChanged(int shuffleMode) {
-        final MediaController2Impl controller;
-        try {
-            controller = getController();
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-            return;
-        }
-        controller.pushShuffleModeChanges(shuffleMode);
-    }
-
-    @Override
-    public void onError(int errorCode, Bundle extras) {
-        final MediaController2Impl controller;
-        try {
-            controller = getController();
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-            return;
-        }
-        controller.pushError(errorCode, extras);
-    }
-
-    @Override
-    public void onConnected(IMediaSession2 sessionBinder, Bundle commandGroup,
-            int playerState, long positionEventTimeMs, long positionMs, float playbackSpeed,
-            long bufferedPositionMs, Bundle playbackInfo, int shuffleMode, int repeatMode,
-            List<Bundle> itemBundleList, PendingIntent sessionActivity) {
-        final MediaController2Impl controller = mController.get();
-        if (controller == null) {
-            if (DEBUG) {
-                Log.d(TAG, "onConnected after MediaController2.close()");
-            }
-            return;
-        }
-        final Context context = controller.getContext();
-        List<MediaItem2> itemList = null;
-        if (itemBundleList != null) {
-            itemList = new ArrayList<>();
-            for (int i = 0; i < itemBundleList.size(); i++) {
-                MediaItem2 item = MediaItem2.fromBundle(itemBundleList.get(i));
-                if (item != null) {
-                    itemList.add(item);
-                }
-            }
-        }
-        controller.onConnectedNotLocked(sessionBinder,
-                SessionCommandGroup2.fromBundle(commandGroup),
-                playerState, positionEventTimeMs, positionMs, playbackSpeed, bufferedPositionMs,
-                PlaybackInfoImpl.fromBundle(playbackInfo), repeatMode, shuffleMode,
-                itemList, sessionActivity);
-    }
-
-    @Override
-    public void onDisconnected() {
-        final MediaController2Impl controller = mController.get();
-        if (controller == null) {
-            if (DEBUG) {
-                Log.d(TAG, "onDisconnected after MediaController2.close()");
-            }
-            return;
-        }
-        controller.getInstance().close();
-    }
-
-    @Override
-    public void onCustomLayoutChanged(List<Bundle> commandButtonlist) {
-        if (commandButtonlist == null) {
-            Log.w(TAG, "onCustomLayoutChanged(): Ignoring null commandButtonlist");
-            return;
-        }
-        final MediaController2Impl controller;
-        try {
-            controller = getController();
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-            return;
-        }
-        if (controller == null) {
-            // TODO(jaewan): Revisit here. Could be a bug
-            return;
-        }
-        List<CommandButton> layout = new ArrayList<>();
-        for (int i = 0; i < commandButtonlist.size(); i++) {
-            CommandButton button = CommandButtonImpl.fromBundle(commandButtonlist.get(i));
-            if (button != null) {
-                layout.add(button);
-            }
-        }
-        controller.onCustomLayoutChanged(layout);
-    }
-
-    @Override
-    public void onAllowedCommandsChanged(Bundle commandsBundle) {
-        final MediaController2Impl controller;
-        try {
-            controller = getController();
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-            return;
-        }
-        if (controller == null) {
-            // TODO(jaewan): Revisit here. Could be a bug
-            return;
-        }
-        SessionCommandGroup2 commands = SessionCommandGroup2.fromBundle(commandsBundle);
-        if (commands == null) {
-            Log.w(TAG, "onAllowedCommandsChanged(): Ignoring null commands");
-            return;
-        }
-        controller.onAllowedCommandsChanged(commands);
-    }
-
-    @Override
-    public void onCustomCommand(Bundle commandBundle, Bundle args, ResultReceiver receiver) {
-        final MediaController2Impl controller;
-        try {
-            controller = getController();
-        } catch (IllegalStateException e) {
-            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
-            return;
-        }
-        SessionCommand2 command = SessionCommand2.fromBundle(commandBundle);
-        if (command == null) {
-            Log.w(TAG, "onCustomCommand(): Ignoring null command");
-            return;
-        }
-        controller.onCustomCommand(command, args, receiver);
-    }
-}
diff --git a/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java b/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
deleted file mode 100644
index 910a0f1..0000000
--- a/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media;
-
-import static android.media.MediaItem2.FLAG_BROWSABLE;
-import static android.media.MediaItem2.FLAG_PLAYABLE;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.media.DataSourceDesc;
-import android.media.MediaItem2;
-import android.media.MediaItem2.Builder;
-import android.media.MediaItem2.Flags;
-import android.media.MediaMetadata2;
-import android.media.update.MediaItem2Provider;
-import android.os.Bundle;
-import android.text.TextUtils;
-
-import java.util.UUID;
-
-public class MediaItem2Impl implements MediaItem2Provider {
-    private static final String KEY_ID = "android.media.mediaitem2.id";
-    private static final String KEY_FLAGS = "android.media.mediaitem2.flags";
-    private static final String KEY_METADATA = "android.media.mediaitem2.metadata";
-    private static final String KEY_UUID = "android.media.mediaitem2.uuid";
-
-    private final MediaItem2 mInstance;
-    private final String mId;
-    private final int mFlags;
-    private final UUID mUUID;
-    private MediaMetadata2 mMetadata;
-    private DataSourceDesc mDataSourceDesc;
-
-    // From the public API
-    public MediaItem2Impl(@NonNull String mediaId, @Nullable DataSourceDesc dsd,
-            @Nullable MediaMetadata2 metadata, @Flags int flags) {
-        this(mediaId, dsd, metadata, flags, null);
-    }
-
-    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");
-        }
-        if (metadata != null && !TextUtils.equals(mediaId, metadata.getMediaId())) {
-            throw new IllegalArgumentException("metadata's id should be matched with the mediaid");
-        }
-
-        mId = mediaId;
-        mDataSourceDesc = dsd;
-        mMetadata = metadata;
-        mFlags = flags;
-        mUUID = (uuid == null) ? UUID.randomUUID() : uuid;
-
-        mInstance = new MediaItem2(this);
-    }
-
-    @Override
-    public boolean equals_impl(Object obj) {
-        if (!(obj instanceof MediaItem2)) {
-            return false;
-        }
-        MediaItem2 other = (MediaItem2) obj;
-        return mUUID.equals(((MediaItem2Impl) other.getProvider()).mUUID);
-    }
-
-    /**
-     * Return this object as a bundle to share between processes.
-     *
-     * @return a new bundle instance
-     */
-    public Bundle toBundle_impl() {
-        Bundle bundle = new Bundle();
-        bundle.putString(KEY_ID, mId);
-        bundle.putInt(KEY_FLAGS, mFlags);
-        if (mMetadata != null) {
-            bundle.putBundle(KEY_METADATA, mMetadata.toBundle());
-        }
-        bundle.putString(KEY_UUID, mUUID.toString());
-        return bundle;
-    }
-
-    /**
-     * Create a MediaItem2 from the {@link Bundle}.
-     *
-     * @param bundle The bundle which was published by {@link MediaItem2#toBundle()}.
-     * @return The newly created MediaItem2
-     */
-    public static MediaItem2 fromBundle_impl(@NonNull Bundle bundle) {
-        if (bundle == null) {
-            return null;
-        }
-        final String uuidString = bundle.getString(KEY_UUID);
-        return fromBundle(bundle, UUID.fromString(uuidString));
-    }
-
-    /**
-     * Create a MediaItem2 from the {@link Bundle} with the specified {@link UUID}.
-     * If {@link UUID}
-     * can be null for creating new.
-     *
-     * @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 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 = MediaMetadata2.fromBundle(metadataBundle);
-        final int flags = bundle.getInt(KEY_FLAGS);
-        return new MediaItem2Impl(id, null, metadata, flags, uuid).getInstance();
-    }
-
-    private MediaItem2 getInstance() {
-        return mInstance;
-    }
-
-    @Override
-    public String toString_impl() {
-        final StringBuilder sb = new StringBuilder("MediaItem2{");
-        sb.append("mFlags=").append(mFlags);
-        sb.append(", mMetadata=").append(mMetadata);
-        sb.append('}');
-        return sb.toString();
-    }
-
-    @Override
-    public @Flags int getFlags_impl() {
-        return mFlags;
-    }
-
-    @Override
-    public boolean isBrowsable_impl() {
-        return (mFlags & FLAG_BROWSABLE) != 0;
-    }
-
-    @Override
-    public boolean isPlayable_impl() {
-        return (mFlags & FLAG_PLAYABLE) != 0;
-    }
-
-    @Override
-    public void setMetadata_impl(@Nullable MediaMetadata2 metadata) {
-        if (metadata != null && !TextUtils.equals(mId, metadata.getMediaId())) {
-            throw new IllegalArgumentException("metadata's id should be matched with the mediaId");
-        }
-        mMetadata = metadata;
-    }
-
-    @Override
-    public @Nullable MediaMetadata2 getMetadata_impl() {
-        return mMetadata;
-    }
-
-    @Override
-    public @NonNull String getMediaId_impl() {
-        return mId;
-    }
-
-    @Override
-    public @Nullable DataSourceDesc getDataSourceDesc_impl() {
-        return mDataSourceDesc;
-    }
-
-    public static class BuilderImpl implements MediaItem2Provider.BuilderProvider {
-        private Builder mInstance;
-        private @Flags int mFlags;
-        private String mMediaId;
-        private MediaMetadata2 mMetadata;
-        private DataSourceDesc mDataSourceDesc;
-
-        public BuilderImpl(Builder instance, int flags) {
-            mInstance = instance;
-            mFlags = flags;
-        }
-
-        @Override
-        public Builder setMediaId_impl(@Nullable String mediaId) {
-            mMediaId = mediaId;
-            return mInstance;
-        }
-
-        @Override
-        public Builder setMetadata_impl(@Nullable MediaMetadata2 metadata) {
-            mMetadata = metadata;
-            return mInstance;
-        }
-
-        @Override
-        public Builder setDataSourceDesc_impl(@Nullable DataSourceDesc dataSourceDesc) {
-            mDataSourceDesc = dataSourceDesc;
-            return mInstance;
-        }
-
-        @Override
-        public MediaItem2 build_impl() {
-            String id = (mMetadata != null)
-                    ? mMetadata.getString(MediaMetadata2.METADATA_KEY_MEDIA_ID) : null;
-            if (id == null) {
-                //  TODO(jaewan): Double check if its sufficient (e.g. Use UUID instead?)
-                id = (mMediaId != null) ? mMediaId : toString();
-            }
-            return new MediaItem2Impl(id, mDataSourceDesc, mMetadata, mFlags).getInstance();
-        }
-    }
-}
diff --git a/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java b/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java
deleted file mode 100644
index cf1c532..0000000
--- a/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media;
-
-import static android.media.MediaMetadata2.*;
-
-import android.annotation.Nullable;
-import android.graphics.Bitmap;
-import android.media.MediaMetadata2;
-import android.media.MediaMetadata2.BitmapKey;
-import android.media.MediaMetadata2.Builder;
-import android.media.MediaMetadata2.LongKey;
-import android.media.MediaMetadata2.RatingKey;
-import android.media.MediaMetadata2.TextKey;
-import android.media.Rating2;
-import android.media.update.MediaMetadata2Provider;
-import android.os.Bundle;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import java.util.Set;
-
-public class MediaMetadata2Impl implements MediaMetadata2Provider {
-    private static final String TAG = "MediaMetadata2";
-
-    static final int METADATA_TYPE_LONG = 0;
-    static final int METADATA_TYPE_TEXT = 1;
-    static final int METADATA_TYPE_BITMAP = 2;
-    static final int METADATA_TYPE_RATING = 3;
-    static final int METADATA_TYPE_FLOAT = 4;
-    static final ArrayMap<String, Integer> METADATA_KEYS_TYPE;
-
-    static {
-        METADATA_KEYS_TYPE = new ArrayMap<String, Integer>();
-        METADATA_KEYS_TYPE.put(METADATA_KEY_TITLE, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_ARTIST, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DURATION, METADATA_TYPE_LONG);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ARTIST, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_ART_URI, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART, METADATA_TYPE_BITMAP);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART_URI, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_TITLE, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_SUBTITLE, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON, METADATA_TYPE_BITMAP);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON_URI, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_ID, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_BT_FOLDER_TYPE, METADATA_TYPE_LONG);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_URI, METADATA_TYPE_TEXT);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_ADVERTISEMENT, METADATA_TYPE_LONG);
-        METADATA_KEYS_TYPE.put(METADATA_KEY_DOWNLOAD_STATUS, METADATA_TYPE_LONG);
-    }
-
-    private static final @TextKey
-    String[] PREFERRED_DESCRIPTION_ORDER = {
-            METADATA_KEY_TITLE,
-            METADATA_KEY_ARTIST,
-            METADATA_KEY_ALBUM,
-            METADATA_KEY_ALBUM_ARTIST,
-            METADATA_KEY_WRITER,
-            METADATA_KEY_AUTHOR,
-            METADATA_KEY_COMPOSER
-    };
-
-    private static final @BitmapKey
-    String[] PREFERRED_BITMAP_ORDER = {
-            METADATA_KEY_DISPLAY_ICON,
-            METADATA_KEY_ART,
-            METADATA_KEY_ALBUM_ART
-    };
-
-    private static final @TextKey
-    String[] PREFERRED_URI_ORDER = {
-            METADATA_KEY_DISPLAY_ICON_URI,
-            METADATA_KEY_ART_URI,
-            METADATA_KEY_ALBUM_ART_URI
-    };
-
-    private final MediaMetadata2 mInstance;
-    private final Bundle mBundle;
-
-    public MediaMetadata2Impl(Bundle bundle) {
-        mInstance = new MediaMetadata2(this);
-        mBundle = bundle;
-    }
-
-    public MediaMetadata2 getInstance() {
-        return mInstance;
-    }
-
-    @Override
-    public boolean containsKey_impl(String key) {
-        if (key == null) {
-            throw new IllegalArgumentException("key shouldn't be null");
-        }
-        return mBundle.containsKey(key);
-    }
-
-    @Override
-    public CharSequence getText_impl(@TextKey String key) {
-        if (key == null) {
-            throw new IllegalArgumentException("key shouldn't be null");
-        }
-        return mBundle.getCharSequence(key);
-    }
-
-    @Override
-    public @Nullable String getMediaId_impl() {
-        return mInstance.getString(METADATA_KEY_MEDIA_ID);
-    }
-
-    @Override
-    public String getString_impl(@TextKey String key) {
-        if (key == null) {
-            throw new IllegalArgumentException("key shouldn't be null");
-        }
-        CharSequence text = mBundle.getCharSequence(key);
-        if (text != null) {
-            return text.toString();
-        }
-        return null;
-    }
-
-    @Override
-    public long getLong_impl(@LongKey String key) {
-        if (key == null) {
-            throw new IllegalArgumentException("key shouldn't be null");
-        }
-        return mBundle.getLong(key, 0);
-    }
-
-    @Override
-    public Rating2 getRating_impl(@RatingKey String key) {
-        if (key == null) {
-            throw new IllegalArgumentException("key shouldn't be null");
-        }
-        // TODO(jaewan): Add backward compatibility
-        Rating2 rating = null;
-        try {
-            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);
-        }
-        return rating;
-    }
-
-    @Override
-    public float getFloat_impl(@FloatKey String key) {
-        if (key == null) {
-            throw new IllegalArgumentException("key shouldn't be null");
-        }
-        return mBundle.getFloat(key);
-    }
-
-    @Override
-    public Bitmap getBitmap_impl(@BitmapKey String key) {
-        if (key == null) {
-            throw new IllegalArgumentException("key shouldn't be null");
-        }
-        Bitmap bmp = null;
-        try {
-            bmp = mBundle.getParcelable(key);
-        } catch (Exception e) {
-            // ignore, value was not a bitmap
-            Log.w(TAG, "Failed to retrieve a key as Bitmap.", e);
-        }
-        return bmp;
-    }
-
-    @Override
-    public Bundle getExtras_impl() {
-        try {
-            return mBundle.getBundle(METADATA_KEY_EXTRAS);
-        } catch (Exception e) {
-            // ignore, value was not an bundle
-            Log.w(TAG, "Failed to retrieve an extra");
-        }
-        return null;
-    }
-
-    @Override
-    public int size_impl() {
-        return mBundle.size();
-    }
-
-    @Override
-    public Set<String> keySet_impl() {
-        return mBundle.keySet();
-    }
-
-    @Override
-    public Bundle toBundle_impl() {
-        return mBundle;
-    }
-
-    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 MediaMetadata2.Builder mInstance;
-        private final Bundle mBundle;
-
-        public BuilderImpl(MediaMetadata2.Builder instance) {
-            mInstance = instance;
-            mBundle = new Bundle();
-        }
-
-        public BuilderImpl(MediaMetadata2.Builder instance, MediaMetadata2 source) {
-            if (source == null) {
-                throw new IllegalArgumentException("source shouldn't be null");
-            }
-            mInstance = instance;
-            mBundle = new Bundle(source.toBundle());
-        }
-
-        public BuilderImpl(int maxBitmapSize) {
-            mInstance = new MediaMetadata2.Builder(this);
-            mBundle = new Bundle();
-
-            for (String key : mBundle.keySet()) {
-                Object value = mBundle.get(key);
-                if (value instanceof Bitmap) {
-                    Bitmap bmp = (Bitmap) value;
-                    if (bmp.getHeight() > maxBitmapSize || bmp.getWidth() > maxBitmapSize) {
-                        mInstance.putBitmap(key, scaleBitmap(bmp, maxBitmapSize));
-                    }
-                }
-            }
-        }
-
-        @Override
-        public Builder putText_impl(@TextKey String key, CharSequence value) {
-            if (key == null) {
-                throw new IllegalArgumentException("key shouldn't be null");
-            }
-            if (METADATA_KEYS_TYPE.containsKey(key)) {
-                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
-                    throw new IllegalArgumentException("The " + key
-                            + " key cannot be used to put a CharSequence");
-                }
-            }
-            mBundle.putCharSequence(key, value);
-            return mInstance;
-        }
-
-        @Override
-        public Builder putString_impl(@TextKey String key, String value) {
-            if (key == null) {
-                throw new IllegalArgumentException("key shouldn't be null");
-            }
-            if (METADATA_KEYS_TYPE.containsKey(key)) {
-                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
-                    throw new IllegalArgumentException("The " + key
-                            + " key cannot be used to put a String");
-                }
-            }
-            mBundle.putCharSequence(key, value);
-            return mInstance;
-        }
-
-        @Override
-        public Builder putLong_impl(@LongKey String key, long value) {
-            if (key == null) {
-                throw new IllegalArgumentException("key shouldn't be null");
-            }
-            if (METADATA_KEYS_TYPE.containsKey(key)) {
-                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_LONG) {
-                    throw new IllegalArgumentException("The " + key
-                            + " key cannot be used to put a long");
-                }
-            }
-            mBundle.putLong(key, value);
-            return mInstance;
-        }
-
-        @Override
-        public Builder putRating_impl(@RatingKey String key, Rating2 value) {
-            if (key == null) {
-                throw new IllegalArgumentException("key shouldn't be null");
-            }
-            if (METADATA_KEYS_TYPE.containsKey(key)) {
-                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_RATING) {
-                    throw new IllegalArgumentException("The " + key
-                            + " key cannot be used to put a Rating");
-                }
-            }
-            mBundle.putBundle(key, value.toBundle());
-            return mInstance;
-        }
-
-        @Override
-        public Builder putBitmap_impl(@BitmapKey String key, Bitmap value) {
-            if (key == null) {
-                throw new IllegalArgumentException("key shouldn't be null");
-            }
-            if (METADATA_KEYS_TYPE.containsKey(key)) {
-                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) {
-                    throw new IllegalArgumentException("The " + key
-                            + " key cannot be used to put a Bitmap");
-                }
-            }
-            mBundle.putParcelable(key, value);
-            return mInstance;
-        }
-
-        @Override
-        public Builder putFloat_impl(@FloatKey String key, float value) {
-            if (key == null) {
-                throw new IllegalArgumentException("key shouldn't be null");
-            }
-            if (METADATA_KEYS_TYPE.containsKey(key)) {
-                if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_FLOAT) {
-                    throw new IllegalArgumentException("The " + key
-                            + " key cannot be used to put a float");
-                }
-            }
-            mBundle.putFloat(key, value);
-            return mInstance;
-        }
-
-        @Override
-        public Builder setExtras_impl(Bundle bundle) {
-            mBundle.putBundle(METADATA_KEY_EXTRAS, bundle);
-            return mInstance;
-        }
-
-        @Override
-        public MediaMetadata2 build_impl() {
-            return new MediaMetadata2Impl(mBundle).getInstance();
-        }
-
-        private Bitmap scaleBitmap(Bitmap bmp, int maxSize) {
-            float maxSizeF = maxSize;
-            float widthScale = maxSizeF / bmp.getWidth();
-            float heightScale = maxSizeF / bmp.getHeight();
-            float scale = Math.min(widthScale, heightScale);
-            int height = (int) (bmp.getHeight() * scale);
-            int width = (int) (bmp.getWidth() * scale);
-            return Bitmap.createScaledBitmap(bmp, width, height, true);
-        }
-    }
-}
-
diff --git a/packages/MediaComponents/src/com/android/media/MediaPlaylistAgentImpl.java b/packages/MediaComponents/src/com/android/media/MediaPlaylistAgentImpl.java
deleted file mode 100644
index dfd4e1a..0000000
--- a/packages/MediaComponents/src/com/android/media/MediaPlaylistAgentImpl.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media;
-
-import android.annotation.CallbackExecutor;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.media.DataSourceDesc;
-import android.media.MediaItem2;
-import android.media.MediaMetadata2;
-import android.media.MediaPlaylistAgent;
-import android.media.MediaPlaylistAgent.PlaylistEventCallback;
-import android.media.update.MediaPlaylistAgentProvider;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.List;
-import java.util.concurrent.Executor;
-
-public class MediaPlaylistAgentImpl implements MediaPlaylistAgentProvider {
-    private static final String TAG = "MediaPlaylistAgent";
-
-    private final MediaPlaylistAgent mInstance;
-
-    private final Object mLock = new Object();
-    @GuardedBy("mLock")
-    private final ArrayMap<PlaylistEventCallback, Executor> mCallbacks = new ArrayMap<>();
-
-    public MediaPlaylistAgentImpl(MediaPlaylistAgent instance) {
-        mInstance = instance;
-    }
-
-    @Override
-    final public void registerPlaylistEventCallback_impl(
-            @NonNull @CallbackExecutor Executor executor, @NonNull PlaylistEventCallback callback) {
-        if (executor == null) {
-            throw new IllegalArgumentException("executor shouldn't be null");
-        }
-        if (callback == null) {
-            throw new IllegalArgumentException("callback shouldn't be null");
-        }
-
-        synchronized (mLock) {
-            if (mCallbacks.get(callback) != null) {
-                Log.w(TAG, "callback is already added. Ignoring.");
-                return;
-            }
-            mCallbacks.put(callback, executor);
-        }
-    }
-
-    @Override
-    final public void unregisterPlaylistEventCallback_impl(
-            @NonNull PlaylistEventCallback callback) {
-        if (callback == null) {
-            throw new IllegalArgumentException("callback shouldn't be null");
-        }
-        synchronized (mLock) {
-            mCallbacks.remove(callback);
-        }
-    }
-
-    @Override
-    final public void notifyPlaylistChanged_impl() {
-        ArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks();
-        List<MediaItem2> playlist= mInstance.getPlaylist();
-        MediaMetadata2 metadata = mInstance.getPlaylistMetadata();
-        for (int i = 0; i < callbacks.size(); i++) {
-            final PlaylistEventCallback callback = callbacks.keyAt(i);
-            final Executor executor = callbacks.valueAt(i);
-            executor.execute(() -> callback.onPlaylistChanged(
-                    mInstance, playlist, metadata));
-        }
-    }
-
-    @Override
-    final public void notifyPlaylistMetadataChanged_impl() {
-        ArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks();
-        for (int i = 0; i < callbacks.size(); i++) {
-            final PlaylistEventCallback callback = callbacks.keyAt(i);
-            final Executor executor = callbacks.valueAt(i);
-            executor.execute(() -> callback.onPlaylistMetadataChanged(
-                    mInstance, mInstance.getPlaylistMetadata()));
-        }
-    }
-
-    @Override
-    final public void notifyShuffleModeChanged_impl() {
-        ArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks();
-        for (int i = 0; i < callbacks.size(); i++) {
-            final PlaylistEventCallback callback = callbacks.keyAt(i);
-            final Executor executor = callbacks.valueAt(i);
-            executor.execute(() -> callback.onShuffleModeChanged(
-                    mInstance, mInstance.getShuffleMode()));
-        }
-    }
-
-    @Override
-    final public void notifyRepeatModeChanged_impl() {
-        ArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks();
-        for (int i = 0; i < callbacks.size(); i++) {
-            final PlaylistEventCallback callback = callbacks.keyAt(i);
-            final Executor executor = callbacks.valueAt(i);
-            executor.execute(() -> callback.onRepeatModeChanged(
-                    mInstance, mInstance.getRepeatMode()));
-        }
-    }
-
-    @Override
-    public @Nullable List<MediaItem2> getPlaylist_impl() {
-        // empty implementation
-        return null;
-    }
-
-    @Override
-    public void setPlaylist_impl(@NonNull List<MediaItem2> list,
-            @Nullable MediaMetadata2 metadata) {
-        // empty implementation
-    }
-
-    @Override
-    public @Nullable MediaMetadata2 getPlaylistMetadata_impl() {
-        // empty implementation
-        return null;
-    }
-
-    @Override
-    public void updatePlaylistMetadata_impl(@Nullable MediaMetadata2 metadata) {
-        // empty implementation
-    }
-
-    @Override
-    public void addPlaylistItem_impl(int index, @NonNull MediaItem2 item) {
-        // empty implementation
-    }
-
-    @Override
-    public void removePlaylistItem_impl(@NonNull MediaItem2 item) {
-        // empty implementation
-    }
-
-    @Override
-    public void replacePlaylistItem_impl(int index, @NonNull MediaItem2 item) {
-        // empty implementation
-    }
-
-    @Override
-    public void skipToPlaylistItem_impl(@NonNull MediaItem2 item) {
-        // empty implementation
-    }
-
-    @Override
-    public void skipToPreviousItem_impl() {
-        // empty implementation
-    }
-
-    @Override
-    public void skipToNextItem_impl() {
-        // empty implementation
-    }
-
-    @Override
-    public int getRepeatMode_impl() {
-        return MediaPlaylistAgent.REPEAT_MODE_NONE;
-    }
-
-    @Override
-    public void setRepeatMode_impl(int repeatMode) {
-        // empty implementation
-    }
-
-    @Override
-    public int getShuffleMode_impl() {
-        // empty implementation
-        return MediaPlaylistAgent.SHUFFLE_MODE_NONE;
-    }
-
-    @Override
-    public void setShuffleMode_impl(int shuffleMode) {
-        // empty implementation
-    }
-
-    @Override
-    public @Nullable MediaItem2 getMediaItem_impl(@NonNull DataSourceDesc dsd) {
-        if (dsd == null) {
-            throw new IllegalArgumentException("dsd shouldn't be null");
-        }
-        List<MediaItem2> itemList = mInstance.getPlaylist();
-        if (itemList == null) {
-            return null;
-        }
-        for (int i = 0; i < itemList.size(); i++) {
-            MediaItem2 item = itemList.get(i);
-            if (item != null && item.getDataSourceDesc() == dsd) {
-                return item;
-            }
-        }
-        return null;
-    }
-
-    private ArrayMap<PlaylistEventCallback, Executor> getCallbacks() {
-        ArrayMap<PlaylistEventCallback, Executor> callbacks = new ArrayMap<>();
-        synchronized (mLock) {
-            callbacks.putAll(mCallbacks);
-        }
-        return callbacks;
-    }
-}
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
deleted file mode 100644
index cd9edb8..0000000
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
+++ /dev/null
@@ -1,1541 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media;
-
-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;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.media.AudioAttributes;
-import android.media.AudioFocusRequest;
-import android.media.AudioManager;
-import android.media.DataSourceDesc;
-import android.media.MediaController2;
-import android.media.MediaController2.PlaybackInfo;
-import android.media.MediaItem2;
-import android.media.MediaMetadata2;
-import android.media.MediaPlayerBase;
-import android.media.MediaPlayerBase.PlayerEventCallback;
-import android.media.MediaPlayerBase.PlayerState;
-import android.media.MediaPlaylistAgent;
-import android.media.MediaPlaylistAgent.PlaylistEventCallback;
-import android.media.MediaSession2;
-import android.media.MediaSession2.Builder;
-import android.media.MediaSession2.CommandButton;
-import android.media.MediaSession2.ControllerInfo;
-import android.media.MediaSession2.OnDataSourceMissingHelper;
-import android.media.MediaSession2.SessionCallback;
-import android.media.SessionCommand2;
-import android.media.SessionCommandGroup2;
-import android.media.SessionToken2;
-import android.media.VolumeProvider2;
-import android.media.session.MediaSessionManager;
-import android.media.update.MediaSession2Provider;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcelable;
-import android.os.Process;
-import android.os.ResultReceiver;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.annotation.GuardedBy;
-
-import java.lang.ref.WeakReference;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.concurrent.Executor;
-
-public class MediaSession2Impl implements MediaSession2Provider {
-    private static final String TAG = "MediaSession2";
-    private static final boolean DEBUG = true;//Log.isLoggable(TAG, Log.DEBUG);
-
-    private final Object mLock = new Object();
-
-    private final MediaSession2 mInstance;
-    private final Context mContext;
-    private final String mId;
-    private final Executor mCallbackExecutor;
-    private final SessionCallback mCallback;
-    private final MediaSession2Stub mSessionStub;
-    private final SessionToken2 mSessionToken;
-    private final AudioManager mAudioManager;
-    private final PendingIntent mSessionActivity;
-    private final PlayerEventCallback mPlayerEventCallback;
-    private final PlaylistEventCallback mPlaylistEventCallback;
-
-    // mPlayer is set to null when the session is closed, and we shouldn't throw an exception
-    // nor leave log always for using mPlayer when it's null. Here's the reason.
-    // When a MediaSession2 is closed, there could be a pended operation in the session callback
-    // executor that may want to access the player. Here's the sample code snippet for that.
-    //
-    //   public void onFoo() {
-    //     if (mPlayer == null) return; // first check
-    //     mSessionCallbackExecutor.executor(() -> {
-    //       // Error. Session may be closed and mPlayer can be null here.
-    //       mPlayer.foo();
-    //     });
-    //   }
-    //
-    // By adding protective code, we can also protect APIs from being called after the close()
-    //
-    // TODO(jaewan): Should we put volatile here?
-    @GuardedBy("mLock")
-    private MediaPlayerBase mPlayer;
-    @GuardedBy("mLock")
-    private MediaPlaylistAgent mPlaylistAgent;
-    @GuardedBy("mLock")
-    private SessionPlaylistAgent mSessionPlaylistAgent;
-    @GuardedBy("mLock")
-    private VolumeProvider2 mVolumeProvider;
-    @GuardedBy("mLock")
-    private PlaybackInfo mPlaybackInfo;
-    @GuardedBy("mLock")
-    private OnDataSourceMissingHelper mDsmHelper;
-
-    /**
-     * Can be only called by the {@link Builder#build()}.
-     * @param context
-     * @param player
-     * @param id
-     * @param playlistAgent
-     * @param volumeProvider
-     * @param sessionActivity
-     * @param callbackExecutor
-     * @param callback
-     */
-    public MediaSession2Impl(Context context, MediaPlayerBase player, String id,
-            MediaPlaylistAgent playlistAgent, VolumeProvider2 volumeProvider,
-            PendingIntent sessionActivity,
-            Executor callbackExecutor, SessionCallback callback) {
-        // TODO(jaewan): Keep other params.
-        mInstance = createInstance();
-
-        // Argument checks are done by builder already.
-        // Initialize finals first.
-        mContext = context;
-        mId = id;
-        mCallback = callback;
-        mCallbackExecutor = callbackExecutor;
-        mSessionActivity = sessionActivity;
-        mSessionStub = new MediaSession2Stub(this);
-        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-        mPlayerEventCallback = new MyPlayerEventCallback(this);
-        mPlaylistEventCallback = new MyPlaylistEventCallback(this);
-
-        // Infer type from the id and package name.
-        mSessionToken = new SessionToken2Impl(Process.myUid(), TYPE_SESSION,
-                mContext.getPackageName(), null, id, mSessionStub).getInstance();
-
-        updatePlayer(player, playlistAgent, volumeProvider);
-
-        // Ask server for the sanity check, and starts
-        // Sanity check for making session ID unique 'per package' cannot be done in here.
-        // Server can only know if the package has another process and has another session with the
-        // same id. Note that 'ID is unique per package' is important for controller to distinguish
-        // a session in another package.
-        MediaSessionManager manager =
-                (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
-        if (!manager.createSession2(mSessionToken)) {
-            throw new IllegalStateException("Session with the same id is already used by"
-                    + " another process. Use MediaController2 instead.");
-        }
-    }
-
-    MediaSession2 createInstance() {
-        return new MediaSession2(this);
-    }
-
-    private static String getServiceName(Context context, String serviceAction, String id) {
-        PackageManager manager = context.getPackageManager();
-        Intent serviceIntent = new Intent(serviceAction);
-        serviceIntent.setPackage(context.getPackageName());
-        List<ResolveInfo> services = manager.queryIntentServices(serviceIntent,
-                PackageManager.GET_META_DATA);
-        String serviceName = null;
-        if (services != null) {
-            for (int i = 0; i < services.size(); i++) {
-                String serviceId = SessionToken2Impl.getSessionId(services.get(i));
-                if (serviceId != null && TextUtils.equals(id, serviceId)) {
-                    if (services.get(i).serviceInfo == null) {
-                        continue;
-                    }
-                    if (serviceName != null) {
-                        throw new IllegalArgumentException("Ambiguous session type. Multiple"
-                                + " session services define the same id=" + id);
-                    }
-                    serviceName = services.get(i).serviceInfo.name;
-                }
-            }
-        }
-        return serviceName;
-    }
-
-    @Override
-    public void updatePlayer_impl(@NonNull MediaPlayerBase player, MediaPlaylistAgent playlistAgent,
-            VolumeProvider2 volumeProvider) throws IllegalArgumentException {
-        ensureCallingThread();
-        if (player == null) {
-            throw new IllegalArgumentException("player shouldn't be null");
-        }
-        updatePlayer(player, playlistAgent, volumeProvider);
-    }
-
-    private void updatePlayer(MediaPlayerBase player, MediaPlaylistAgent agent,
-            VolumeProvider2 volumeProvider) {
-        final MediaPlayerBase oldPlayer;
-        final MediaPlaylistAgent oldAgent;
-        final PlaybackInfo info = createPlaybackInfo(volumeProvider, player.getAudioAttributes());
-        synchronized (mLock) {
-            oldPlayer = mPlayer;
-            oldAgent = mPlaylistAgent;
-            mPlayer = player;
-            if (agent == null) {
-                mSessionPlaylistAgent = new SessionPlaylistAgent(this, mPlayer);
-                if (mDsmHelper != null) {
-                    mSessionPlaylistAgent.setOnDataSourceMissingHelper(mDsmHelper);
-                }
-                agent = mSessionPlaylistAgent;
-            }
-            mPlaylistAgent = agent;
-            mVolumeProvider = volumeProvider;
-            mPlaybackInfo = info;
-        }
-        if (player != oldPlayer) {
-            player.registerPlayerEventCallback(mCallbackExecutor, mPlayerEventCallback);
-            if (oldPlayer != null) {
-                // Warning: Poorly implement player may ignore this
-                oldPlayer.unregisterPlayerEventCallback(mPlayerEventCallback);
-            }
-        }
-        if (agent != oldAgent) {
-            agent.registerPlaylistEventCallback(mCallbackExecutor, mPlaylistEventCallback);
-            if (oldAgent != null) {
-                // Warning: Poorly implement player may ignore this
-                oldAgent.unregisterPlaylistEventCallback(mPlaylistEventCallback);
-            }
-        }
-
-        if (oldPlayer != null) {
-            mSessionStub.notifyPlaybackInfoChanged(info);
-            notifyPlayerUpdatedNotLocked(oldPlayer);
-        }
-        // TODO(jaewan): Repeat the same thing for the playlist agent.
-    }
-
-    private PlaybackInfo createPlaybackInfo(VolumeProvider2 volumeProvider, AudioAttributes attrs) {
-        PlaybackInfo info;
-        if (volumeProvider == null) {
-            int stream;
-            if (attrs == null) {
-                stream = AudioManager.STREAM_MUSIC;
-            } else {
-                stream = attrs.getVolumeControlStream();
-                if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) {
-                    // It may happen if the AudioAttributes doesn't have usage.
-                    // Change it to the STREAM_MUSIC because it's not supported by audio manager
-                    // for querying volume level.
-                    stream = AudioManager.STREAM_MUSIC;
-                }
-            }
-            info = MediaController2Impl.PlaybackInfoImpl.createPlaybackInfo(
-                    PlaybackInfo.PLAYBACK_TYPE_LOCAL,
-                    attrs,
-                    mAudioManager.isVolumeFixed()
-                            ? VolumeProvider2.VOLUME_CONTROL_FIXED
-                            : VolumeProvider2.VOLUME_CONTROL_ABSOLUTE,
-                    mAudioManager.getStreamMaxVolume(stream),
-                    mAudioManager.getStreamVolume(stream));
-        } else {
-            info = MediaController2Impl.PlaybackInfoImpl.createPlaybackInfo(
-                    PlaybackInfo.PLAYBACK_TYPE_REMOTE /* ControlType */,
-                    attrs,
-                    volumeProvider.getControlType(),
-                    volumeProvider.getMaxVolume(),
-                    volumeProvider.getCurrentVolume());
-        }
-        return info;
-    }
-
-    @Override
-    public void close_impl() {
-        // Stop system service from listening this session first.
-        MediaSessionManager manager =
-                (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
-        manager.destroySession2(mSessionToken);
-
-        if (mSessionStub != null) {
-            if (DEBUG) {
-                Log.d(TAG, "session is now unavailable, id=" + mId);
-            }
-            // Invalidate previously published session stub.
-            mSessionStub.destroyNotLocked();
-        }
-        final MediaPlayerBase player;
-        final MediaPlaylistAgent agent;
-        synchronized (mLock) {
-            player = mPlayer;
-            mPlayer = null;
-            agent = mPlaylistAgent;
-            mPlaylistAgent = null;
-            mSessionPlaylistAgent = null;
-        }
-        if (player != null) {
-            player.unregisterPlayerEventCallback(mPlayerEventCallback);
-        }
-        if (agent != null) {
-            agent.unregisterPlaylistEventCallback(mPlaylistEventCallback);
-        }
-    }
-
-    @Override
-    public MediaPlayerBase getPlayer_impl() {
-        return getPlayer();
-    }
-
-    @Override
-    public MediaPlaylistAgent getPlaylistAgent_impl() {
-        return mPlaylistAgent;
-    }
-
-    @Override
-    public VolumeProvider2 getVolumeProvider_impl() {
-        return mVolumeProvider;
-    }
-
-    @Override
-    public SessionToken2 getToken_impl() {
-        return mSessionToken;
-    }
-
-    @Override
-    public List<ControllerInfo> getConnectedControllers_impl() {
-        return mSessionStub.getControllers();
-    }
-
-    @Override
-    public void setAudioFocusRequest_impl(AudioFocusRequest afr) {
-        // implement
-    }
-
-    @Override
-    public void play_impl() {
-        ensureCallingThread();
-        final MediaPlayerBase player = mPlayer;
-        if (player != null) {
-            player.play();
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void pause_impl() {
-        ensureCallingThread();
-        final MediaPlayerBase player = mPlayer;
-        if (player != null) {
-            player.pause();
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void stop_impl() {
-        ensureCallingThread();
-        final MediaPlayerBase player = mPlayer;
-        if (player != null) {
-            player.reset();
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void skipToPlaylistItem_impl(@NonNull MediaItem2 item) {
-        if (item == null) {
-            throw new IllegalArgumentException("item shouldn't be null");
-        }
-        final MediaPlaylistAgent agent = mPlaylistAgent;
-        if (agent != null) {
-            agent.skipToPlaylistItem(item);
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void skipToPreviousItem_impl() {
-        final MediaPlaylistAgent agent = mPlaylistAgent;
-        if (agent != null) {
-            agent.skipToPreviousItem();
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void skipToNextItem_impl() {
-        final MediaPlaylistAgent agent = mPlaylistAgent;
-        if (agent != null) {
-            agent.skipToNextItem();
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void setCustomLayout_impl(@NonNull ControllerInfo controller,
-            @NonNull List<CommandButton> layout) {
-        ensureCallingThread();
-        if (controller == null) {
-            throw new IllegalArgumentException("controller shouldn't be null");
-        }
-        if (layout == null) {
-            throw new IllegalArgumentException("layout shouldn't be null");
-        }
-        mSessionStub.notifyCustomLayoutNotLocked(controller, layout);
-    }
-
-    //////////////////////////////////////////////////////////////////////////////////////
-    // TODO(jaewan): Implement follows
-    //////////////////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public void setAllowedCommands_impl(@NonNull ControllerInfo controller,
-            @NonNull SessionCommandGroup2 commands) {
-        if (controller == null) {
-            throw new IllegalArgumentException("controller shouldn't be null");
-        }
-        if (commands == null) {
-            throw new IllegalArgumentException("commands shouldn't be null");
-        }
-        mSessionStub.setAllowedCommands(controller, commands);
-    }
-
-    @Override
-    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");
-        }
-        if (command == null) {
-            throw new IllegalArgumentException("command shouldn't be null");
-        }
-        mSessionStub.sendCustomCommand(controller, command, args, receiver);
-    }
-
-    @Override
-    public void sendCustomCommand_impl(@NonNull SessionCommand2 command, Bundle args) {
-        if (command == null) {
-            throw new IllegalArgumentException("command shouldn't be null");
-        }
-        mSessionStub.sendCustomCommand(command, args);
-    }
-
-    @Override
-    public void setPlaylist_impl(@NonNull List<MediaItem2> list, MediaMetadata2 metadata) {
-        if (list == null) {
-            throw new IllegalArgumentException("list shouldn't be null");
-        }
-        ensureCallingThread();
-        final MediaPlaylistAgent agent = mPlaylistAgent;
-        if (agent != null) {
-            agent.setPlaylist(list, metadata);
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void updatePlaylistMetadata_impl(MediaMetadata2 metadata) {
-        final MediaPlaylistAgent agent = mPlaylistAgent;
-        if (agent != null) {
-            agent.updatePlaylistMetadata(metadata);
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void addPlaylistItem_impl(int index, @NonNull MediaItem2 item) {
-        if (index < 0) {
-            throw new IllegalArgumentException("index shouldn't be negative");
-        }
-        if (item == null) {
-            throw new IllegalArgumentException("item shouldn't be null");
-        }
-        final MediaPlaylistAgent agent = mPlaylistAgent;
-        if (agent != null) {
-            agent.addPlaylistItem(index, item);
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void removePlaylistItem_impl(@NonNull MediaItem2 item) {
-        if (item == null) {
-            throw new IllegalArgumentException("item shouldn't be null");
-        }
-        final MediaPlaylistAgent agent = mPlaylistAgent;
-        if (agent != null) {
-            agent.removePlaylistItem(item);
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void replacePlaylistItem_impl(int index, @NonNull MediaItem2 item) {
-        if (index < 0) {
-            throw new IllegalArgumentException("index shouldn't be negative");
-        }
-        if (item == null) {
-            throw new IllegalArgumentException("item shouldn't be null");
-        }
-        final MediaPlaylistAgent agent = mPlaylistAgent;
-        if (agent != null) {
-            agent.replacePlaylistItem(index, item);
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public List<MediaItem2> getPlaylist_impl() {
-        final MediaPlaylistAgent agent = mPlaylistAgent;
-        if (agent != null) {
-            return agent.getPlaylist();
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-        return null;
-    }
-
-    @Override
-    public MediaMetadata2 getPlaylistMetadata_impl() {
-        final MediaPlaylistAgent agent = mPlaylistAgent;
-        if (agent != null) {
-            return agent.getPlaylistMetadata();
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-        return null;
-    }
-
-    @Override
-    public MediaItem2 getCurrentPlaylistItem_impl() {
-        // TODO(jaewan): Implement
-        return null;
-    }
-
-    @Override
-    public int getRepeatMode_impl() {
-        final MediaPlaylistAgent agent = mPlaylistAgent;
-        if (agent != null) {
-            return agent.getRepeatMode();
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-        return MediaPlaylistAgent.REPEAT_MODE_NONE;
-    }
-
-    @Override
-    public void setRepeatMode_impl(int repeatMode) {
-        final MediaPlaylistAgent agent = mPlaylistAgent;
-        if (agent != null) {
-            agent.setRepeatMode(repeatMode);
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public int getShuffleMode_impl() {
-        final MediaPlaylistAgent agent = mPlaylistAgent;
-        if (agent != null) {
-            return agent.getShuffleMode();
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-        return MediaPlaylistAgent.SHUFFLE_MODE_NONE;
-    }
-
-    @Override
-    public void setShuffleMode_impl(int shuffleMode) {
-        final MediaPlaylistAgent agent = mPlaylistAgent;
-        if (agent != null) {
-            agent.setShuffleMode(shuffleMode);
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public void prepare_impl() {
-        ensureCallingThread();
-        final MediaPlayerBase player = mPlayer;
-        if (player != null) {
-            player.prepare();
-        } 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;
-        if (player != null) {
-            player.seekTo(pos);
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-    }
-
-    @Override
-    public @PlayerState int getPlayerState_impl() {
-        final MediaPlayerBase player = mPlayer;
-        if (player != null) {
-            return mPlayer.getPlayerState();
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-        return MediaPlayerBase.PLAYER_STATE_ERROR;
-    }
-
-    @Override
-    public long getCurrentPosition_impl() {
-        final MediaPlayerBase player = mPlayer;
-        if (player != null) {
-            return mPlayer.getCurrentPosition();
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-        return MediaPlayerBase.UNKNOWN_TIME;
-    }
-
-    @Override
-    public long getBufferedPosition_impl() {
-        final MediaPlayerBase player = mPlayer;
-        if (player != null) {
-            return mPlayer.getBufferedPosition();
-        } else if (DEBUG) {
-            Log.d(TAG, "API calls after the close()", new IllegalStateException());
-        }
-        return MediaPlayerBase.UNKNOWN_TIME;
-    }
-
-    @Override
-    public void notifyError_impl(int errorCode, Bundle extras) {
-        mSessionStub.notifyError(errorCode, extras);
-    }
-
-    @Override
-    public void setOnDataSourceMissingHelper_impl(@NonNull OnDataSourceMissingHelper helper) {
-        if (helper == null) {
-            throw new IllegalArgumentException("helper shouldn't be null");
-        }
-        synchronized (mLock) {
-            mDsmHelper = helper;
-            if (mSessionPlaylistAgent != null) {
-                mSessionPlaylistAgent.setOnDataSourceMissingHelper(helper);
-            }
-        }
-    }
-
-    @Override
-    public void clearOnDataSourceMissingHelper_impl() {
-        synchronized (mLock) {
-            mDsmHelper = null;
-            if (mSessionPlaylistAgent != null) {
-                mSessionPlaylistAgent.clearOnDataSourceMissingHelper();
-            }
-        }
-    }
-
-    ///////////////////////////////////////////////////
-    // Protected or private methods
-    ///////////////////////////////////////////////////
-
-    // Enforces developers to call all the methods on the initially given thread
-    // because calls from the MediaController2 will be run on the thread.
-    // TODO(jaewan): Should we allow calls from the multiple thread?
-    //               I prefer this way because allowing multiple thread may case tricky issue like
-    //               b/63446360. If the {@link #setPlayer()} with {@code null} can be called from
-    //               another thread, transport controls can be called after that.
-    //               That's basically the developer's mistake, but they cannot understand what's
-    //               happening behind until we tell them so.
-    //               If enforcing callling thread doesn't look good, we can alternatively pick
-    //               1. Allow calls from random threads for all methods.
-    //               2. Allow calls from random threads for all methods, except for the
-    //                  {@link #setPlayer()}.
-    void ensureCallingThread() {
-        // TODO(jaewan): Uncomment or remove
-        /*
-        if (mHandler.getLooper() != Looper.myLooper()) {
-            throw new IllegalStateException("Run this on the given thread");
-        }*/
-    }
-
-    private void notifyPlaylistChangedOnExecutor(MediaPlaylistAgent playlistAgent,
-            List<MediaItem2> list, MediaMetadata2 metadata) {
-        if (playlistAgent != mPlaylistAgent) {
-            // Ignore calls from the old agent.
-            return;
-        }
-        mCallback.onPlaylistChanged(mInstance, playlistAgent, list, metadata);
-        mSessionStub.notifyPlaylistChangedNotLocked(list, metadata);
-    }
-
-    private void notifyPlaylistMetadataChangedOnExecutor(MediaPlaylistAgent playlistAgent,
-            MediaMetadata2 metadata) {
-        if (playlistAgent != mPlaylistAgent) {
-            // Ignore calls from the old agent.
-            return;
-        }
-        mCallback.onPlaylistMetadataChanged(mInstance, playlistAgent, metadata);
-        mSessionStub.notifyPlaylistMetadataChangedNotLocked(metadata);
-    }
-
-    private void notifyRepeatModeChangedOnExecutor(MediaPlaylistAgent playlistAgent,
-            int repeatMode) {
-        if (playlistAgent != mPlaylistAgent) {
-            // Ignore calls from the old agent.
-            return;
-        }
-        mCallback.onRepeatModeChanged(mInstance, playlistAgent, repeatMode);
-        mSessionStub.notifyRepeatModeChangedNotLocked(repeatMode);
-    }
-
-    private void notifyShuffleModeChangedOnExecutor(MediaPlaylistAgent playlistAgent,
-            int shuffleMode) {
-        if (playlistAgent != mPlaylistAgent) {
-            // Ignore calls from the old agent.
-            return;
-        }
-        mCallback.onShuffleModeChanged(mInstance, playlistAgent, shuffleMode);
-        mSessionStub.notifyShuffleModeChangedNotLocked(shuffleMode);
-    }
-
-    private void notifyPlayerUpdatedNotLocked(MediaPlayerBase oldPlayer) {
-        final MediaPlayerBase player = mPlayer;
-        // TODO(jaewan): (Can be post-P) Find better way for player.getPlayerState() //
-        //               In theory, Session.getXXX() may not be the same as Player.getXXX()
-        //               and we should notify information of the session.getXXX() instead of
-        //               player.getXXX()
-        // Notify to controllers as well.
-        final int state = player.getPlayerState();
-        if (state != oldPlayer.getPlayerState()) {
-            mSessionStub.notifyPlayerStateChangedNotLocked(state);
-        }
-
-        final long currentTimeMs = System.currentTimeMillis();
-        final long position = player.getCurrentPosition();
-        if (position != oldPlayer.getCurrentPosition()) {
-            mSessionStub.notifyPositionChangedNotLocked(currentTimeMs, position);
-        }
-
-        final float speed = player.getPlaybackSpeed();
-        if (speed != oldPlayer.getPlaybackSpeed()) {
-            mSessionStub.notifyPlaybackSpeedChangedNotLocked(speed);
-        }
-
-        final long bufferedPosition = player.getBufferedPosition();
-        if (bufferedPosition != oldPlayer.getBufferedPosition()) {
-            mSessionStub.notifyBufferedPositionChangedNotLocked(bufferedPosition);
-        }
-    }
-
-    Context getContext() {
-        return mContext;
-    }
-
-    MediaSession2 getInstance() {
-        return mInstance;
-    }
-
-    MediaPlayerBase getPlayer() {
-        return mPlayer;
-    }
-
-    MediaPlaylistAgent getPlaylistAgent() {
-        return mPlaylistAgent;
-    }
-
-    Executor getCallbackExecutor() {
-        return mCallbackExecutor;
-    }
-
-    SessionCallback getCallback() {
-        return mCallback;
-    }
-
-    MediaSession2Stub getSessionStub() {
-        return mSessionStub;
-    }
-
-    VolumeProvider2 getVolumeProvider() {
-        return mVolumeProvider;
-    }
-
-    PlaybackInfo getPlaybackInfo() {
-        synchronized (mLock) {
-            return mPlaybackInfo;
-        }
-    }
-
-    PendingIntent getSessionActivity() {
-        return mSessionActivity;
-    }
-
-    private static class MyPlayerEventCallback extends PlayerEventCallback {
-        private final WeakReference<MediaSession2Impl> mSession;
-
-        private MyPlayerEventCallback(MediaSession2Impl session) {
-            mSession = new WeakReference<>(session);
-        }
-
-        @Override
-        public void onCurrentDataSourceChanged(MediaPlayerBase mpb, DataSourceDesc dsd) {
-            MediaSession2Impl session = getSession();
-            if (session == null || dsd == null) {
-                return;
-            }
-            session.getCallbackExecutor().execute(() -> {
-                MediaItem2 item = getMediaItem(session, dsd);
-                if (item == null) {
-                    return;
-                }
-                session.getCallback().onCurrentMediaItemChanged(session.getInstance(), mpb, item);
-                // TODO (jaewan): Notify controllers through appropriate callback. (b/74505936)
-            });
-        }
-
-        @Override
-        public void onMediaPrepared(MediaPlayerBase mpb, DataSourceDesc dsd) {
-            MediaSession2Impl session = getSession();
-            if (session == null || dsd == null) {
-                return;
-            }
-            session.getCallbackExecutor().execute(() -> {
-                MediaItem2 item = getMediaItem(session, dsd);
-                if (item == null) {
-                    return;
-                }
-                session.getCallback().onMediaPrepared(session.getInstance(), mpb, item);
-                // TODO (jaewan): Notify controllers through appropriate callback. (b/74505936)
-            });
-        }
-
-        @Override
-        public void onPlayerStateChanged(MediaPlayerBase mpb, int state) {
-            MediaSession2Impl session = getSession();
-            if (session == null) {
-                return;
-            }
-            session.getCallbackExecutor().execute(() -> {
-                session.getCallback().onPlayerStateChanged(session.getInstance(), mpb, state);
-                session.getSessionStub().notifyPlayerStateChangedNotLocked(state);
-            });
-        }
-
-        @Override
-        public void onBufferingStateChanged(MediaPlayerBase mpb, DataSourceDesc dsd, int state) {
-            MediaSession2Impl session = getSession();
-            if (session == null || dsd == null) {
-                return;
-            }
-            session.getCallbackExecutor().execute(() -> {
-                MediaItem2 item = getMediaItem(session, dsd);
-                if (item == null) {
-                    return;
-                }
-                session.getCallback().onBufferingStateChanged(
-                        session.getInstance(), mpb, item, state);
-                // TODO (jaewan): Notify controllers through appropriate callback. (b/74505936)
-            });
-        }
-
-        private MediaSession2Impl getSession() {
-            final MediaSession2Impl session = mSession.get();
-            if (session == null && DEBUG) {
-                Log.d(TAG, "Session is closed", new IllegalStateException());
-            }
-            return session;
-        }
-
-        private MediaItem2 getMediaItem(MediaSession2Impl session, DataSourceDesc dsd) {
-            MediaPlaylistAgent agent = session.getPlaylistAgent();
-            if (agent == null) {
-                if (DEBUG) {
-                    Log.d(TAG, "Session is closed", new IllegalStateException());
-                }
-                return null;
-            }
-            MediaItem2 item = agent.getMediaItem(dsd);
-            if (item == null) {
-                if (DEBUG) {
-                    Log.d(TAG, "Could not find matching item for dsd=" + dsd,
-                            new NoSuchElementException());
-                }
-            }
-            return item;
-        }
-    }
-
-    private static class MyPlaylistEventCallback extends PlaylistEventCallback {
-        private final WeakReference<MediaSession2Impl> mSession;
-
-        private MyPlaylistEventCallback(MediaSession2Impl session) {
-            mSession = new WeakReference<>(session);
-        }
-
-        @Override
-        public void onPlaylistChanged(MediaPlaylistAgent playlistAgent, List<MediaItem2> list,
-                MediaMetadata2 metadata) {
-            final MediaSession2Impl session = mSession.get();
-            if (session == null) {
-                return;
-            }
-            session.notifyPlaylistChangedOnExecutor(playlistAgent, list, metadata);
-        }
-
-        @Override
-        public void onPlaylistMetadataChanged(MediaPlaylistAgent playlistAgent,
-                MediaMetadata2 metadata) {
-            final MediaSession2Impl session = mSession.get();
-            if (session == null) {
-                return;
-            }
-            session.notifyPlaylistMetadataChangedOnExecutor(playlistAgent, metadata);
-        }
-
-        @Override
-        public void onRepeatModeChanged(MediaPlaylistAgent playlistAgent, int repeatMode) {
-            final MediaSession2Impl session = mSession.get();
-            if (session == null) {
-                return;
-            }
-            session.notifyRepeatModeChangedOnExecutor(playlistAgent, repeatMode);
-        }
-
-        @Override
-        public void onShuffleModeChanged(MediaPlaylistAgent playlistAgent, int shuffleMode) {
-            final MediaSession2Impl session = mSession.get();
-            if (session == null) {
-                return;
-            }
-            session.notifyShuffleModeChangedOnExecutor(playlistAgent, shuffleMode);
-        }
-    }
-
-    public static final class CommandImpl implements CommandProvider {
-        private static final String KEY_COMMAND_CODE
-                = "android.media.media_session2.command.command_code";
-        private static final String KEY_COMMAND_CUSTOM_COMMAND
-                = "android.media.media_session2.command.custom_command";
-        private static final String KEY_COMMAND_EXTRAS
-                = "android.media.media_session2.command.extras";
-
-        private final SessionCommand2 mInstance;
-        private final int mCommandCode;
-        // Nonnull if it's custom command
-        private final String mCustomCommand;
-        private final Bundle mExtras;
-
-        public CommandImpl(SessionCommand2 instance, int commandCode) {
-            mInstance = instance;
-            mCommandCode = commandCode;
-            mCustomCommand = null;
-            mExtras = null;
-        }
-
-        public CommandImpl(SessionCommand2 instance, @NonNull String action,
-                @Nullable Bundle extras) {
-            if (action == null) {
-                throw new IllegalArgumentException("action shouldn't be null");
-            }
-            mInstance = instance;
-            mCommandCode = COMMAND_CODE_CUSTOM;
-            mCustomCommand = action;
-            mExtras = extras;
-        }
-
-        @Override
-        public int getCommandCode_impl() {
-            return mCommandCode;
-        }
-
-        @Override
-        public @Nullable String getCustomCommand_impl() {
-            return mCustomCommand;
-        }
-
-        @Override
-        public @Nullable Bundle getExtras_impl() {
-            return mExtras;
-        }
-
-        /**
-         * @return a new Bundle instance from the Command
-         */
-        @Override
-        public Bundle toBundle_impl() {
-            Bundle bundle = new Bundle();
-            bundle.putInt(KEY_COMMAND_CODE, mCommandCode);
-            bundle.putString(KEY_COMMAND_CUSTOM_COMMAND, mCustomCommand);
-            bundle.putBundle(KEY_COMMAND_EXTRAS, mExtras);
-            return bundle;
-        }
-
-        /**
-         * @return a new Command instance from the Bundle
-         */
-        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 SessionCommand2(code);
-            } else {
-                String customCommand = command.getString(KEY_COMMAND_CUSTOM_COMMAND);
-                if (customCommand == null) {
-                    return null;
-                }
-                return new SessionCommand2(customCommand, command.getBundle(KEY_COMMAND_EXTRAS));
-            }
-        }
-
-        @Override
-        public boolean equals_impl(Object obj) {
-            if (!(obj instanceof CommandImpl)) {
-                return false;
-            }
-            CommandImpl other = (CommandImpl) obj;
-            // TODO(jaewan): Compare Commands with the generated UUID, as we're doing for the MI2.
-            return mCommandCode == other.mCommandCode
-                    && TextUtils.equals(mCustomCommand, other.mCustomCommand);
-        }
-
-        @Override
-        public int hashCode_impl() {
-            final int prime = 31;
-            return ((mCustomCommand != null)
-                    ? mCustomCommand.hashCode() : 0) * prime + mCommandCode;
-        }
-    }
-
-    /**
-     * Represent set of {@link SessionCommand2}.
-     */
-    public static class CommandGroupImpl implements CommandGroupProvider {
-        private static final String KEY_COMMANDS =
-                "android.media.mediasession2.commandgroup.commands";
-
-        // Prefix for all command codes
-        private static final String PREFIX_COMMAND_CODE = "COMMAND_CODE_";
-
-        // Prefix for command codes that will be sent directly to the MediaPlayerBase
-        private static final String PREFIX_COMMAND_CODE_PLAYBACK = "COMMAND_CODE_PLAYBACK_";
-
-        // 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<SessionCommand2> mCommands = new HashSet<>();
-        private final SessionCommandGroup2 mInstance;
-
-        public CommandGroupImpl(SessionCommandGroup2 instance, Object other) {
-            mInstance = instance;
-            if (other != null && other instanceof CommandGroupImpl) {
-                mCommands.addAll(((CommandGroupImpl) other).mCommands);
-            }
-        }
-
-        public CommandGroupImpl() {
-            mInstance = new SessionCommandGroup2(this);
-        }
-
-        @Override
-        public void addCommand_impl(@NonNull SessionCommand2 command) {
-            if (command == null) {
-                throw new IllegalArgumentException("command shouldn't be null");
-            }
-            mCommands.add(command);
-        }
-
-        @Override
-        public void addAllPredefinedCommands_impl() {
-            addCommandsWithPrefix(PREFIX_COMMAND_CODE);
-        }
-
-        void addAllPlaybackCommands() {
-            addCommandsWithPrefix(PREFIX_COMMAND_CODE_PLAYBACK);
-        }
-
-        void addAllPlaylistCommands() {
-            addCommandsWithPrefix(PREFIX_COMMAND_CODE_PLAYLIST);
-        }
-
-        private void addCommandsWithPrefix(String prefix) {
-            // TODO(jaewan): (Can be post-P): Don't use reflection for this purpose.
-            final Field[] fields = MediaSession2.class.getFields();
-            if (fields != null) {
-                for (int i = 0; i < fields.length; i++) {
-                    if (fields[i].getName().startsWith(prefix)) {
-                        try {
-                            mCommands.add(new SessionCommand2(fields[i].getInt(null)));
-                        } catch (IllegalAccessException e) {
-                            Log.w(TAG, "Unexpected " + fields[i] + " in MediaSession2");
-                        }
-                    }
-                }
-            }
-        }
-
-        @Override
-        public void removeCommand_impl(@NonNull SessionCommand2 command) {
-            if (command == null) {
-                throw new IllegalArgumentException("command shouldn't be null");
-            }
-            mCommands.remove(command);
-        }
-
-        @Override
-        public boolean hasCommand_impl(@NonNull SessionCommand2 command) {
-            if (command == null) {
-                throw new IllegalArgumentException("command shouldn't be null");
-            }
-            return mCommands.contains(command);
-        }
-
-        @Override
-        public boolean hasCommand_impl(int code) {
-            if (code == COMMAND_CODE_CUSTOM) {
-                throw new IllegalArgumentException("Use hasCommand(Command) for custom command");
-            }
-            for (SessionCommand2 command : mCommands) {
-                if (command.getCommandCode() == code) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        @Override
-        public Set<SessionCommand2> getCommands_impl() {
-            return getCommands();
-        }
-
-        public Set<SessionCommand2> getCommands() {
-            return Collections.unmodifiableSet(mCommands);
-        }
-
-        /**
-         * @return new bundle from the CommandGroup
-         * @hide
-         */
-        @Override
-        public Bundle toBundle_impl() {
-            ArrayList<Bundle> list = new ArrayList<>();
-            for (SessionCommand2 command : mCommands) {
-                list.add(command.toBundle());
-            }
-            Bundle bundle = new Bundle();
-            bundle.putParcelableArrayList(KEY_COMMANDS, list);
-            return bundle;
-        }
-
-        /**
-         * @return new instance of CommandGroup from the bundle
-         * @hide
-         */
-        public static @Nullable SessionCommandGroup2 fromBundle_impl(Bundle commands) {
-            if (commands == null) {
-                return null;
-            }
-            List<Parcelable> list = commands.getParcelableArrayList(KEY_COMMANDS);
-            if (list == null) {
-                return null;
-            }
-            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;
-                SessionCommand2 command = SessionCommand2.fromBundle(commandBundle);
-                if (command != null) {
-                    commandGroup.addCommand(command);
-                }
-            }
-            return commandGroup;
-        }
-    }
-
-    public static class ControllerInfoImpl implements ControllerInfoProvider {
-        private final ControllerInfo mInstance;
-        private final int mUid;
-        private final String mPackageName;
-        private final boolean mIsTrusted;
-        private final IMediaController2 mControllerBinder;
-
-        public ControllerInfoImpl(Context context, ControllerInfo instance, int uid,
-                int pid, @NonNull String packageName, @NonNull IMediaController2 callback) {
-            if (TextUtils.isEmpty(packageName)) {
-                throw new IllegalArgumentException("packageName shouldn't be empty");
-            }
-            if (callback == null) {
-                throw new IllegalArgumentException("callback shouldn't be null");
-            }
-
-            mInstance = instance;
-            mUid = uid;
-            mPackageName = packageName;
-            mControllerBinder = callback;
-            MediaSessionManager manager =
-                  (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
-            // Ask server whether the controller is trusted.
-            // App cannot know this because apps cannot query enabled notification listener for
-            // another package, but system server can do.
-            mIsTrusted = manager.isTrustedForMediaControl(
-                    new MediaSessionManager.RemoteUserInfo(packageName, pid, uid));
-        }
-
-        @Override
-        public String getPackageName_impl() {
-            return mPackageName;
-        }
-
-        @Override
-        public int getUid_impl() {
-            return mUid;
-        }
-
-        @Override
-        public boolean isTrusted_impl() {
-            return mIsTrusted;
-        }
-
-        @Override
-        public int hashCode_impl() {
-            return mControllerBinder.hashCode();
-        }
-
-        @Override
-        public boolean equals_impl(Object obj) {
-            if (!(obj instanceof ControllerInfo)) {
-                return false;
-            }
-            return equals(((ControllerInfo) obj).getProvider());
-        }
-
-        @Override
-        public String toString_impl() {
-            return "ControllerInfo {pkg=" + mPackageName + ", uid=" + mUid + ", trusted="
-                    + mIsTrusted + "}";
-        }
-
-        @Override
-        public int hashCode() {
-            return mControllerBinder.hashCode();
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof ControllerInfoImpl)) {
-                return false;
-            }
-            ControllerInfoImpl other = (ControllerInfoImpl) obj;
-            return mControllerBinder.asBinder().equals(other.mControllerBinder.asBinder());
-        }
-
-        ControllerInfo getInstance() {
-            return mInstance;
-        }
-
-        IBinder getId() {
-            return mControllerBinder.asBinder();
-        }
-
-        IMediaController2 getControllerBinder() {
-            return mControllerBinder;
-        }
-
-        static ControllerInfoImpl from(ControllerInfo controller) {
-            return (ControllerInfoImpl) controller.getProvider();
-        }
-    }
-
-    public static class CommandButtonImpl implements CommandButtonProvider {
-        private static final String KEY_COMMAND
-                = "android.media.media_session2.command_button.command";
-        private static final String KEY_ICON_RES_ID
-                = "android.media.media_session2.command_button.icon_res_id";
-        private static final String KEY_DISPLAY_NAME
-                = "android.media.media_session2.command_button.display_name";
-        private static final String KEY_EXTRAS
-                = "android.media.media_session2.command_button.extras";
-        private static final String KEY_ENABLED
-                = "android.media.media_session2.command_button.enabled";
-
-        private final CommandButton mInstance;
-        private SessionCommand2 mCommand;
-        private int mIconResId;
-        private String mDisplayName;
-        private Bundle mExtras;
-        private boolean mEnabled;
-
-        public CommandButtonImpl(@Nullable SessionCommand2 command, int iconResId,
-                @Nullable String displayName, Bundle extras, boolean enabled) {
-            mCommand = command;
-            mIconResId = iconResId;
-            mDisplayName = displayName;
-            mExtras = extras;
-            mEnabled = enabled;
-            mInstance = new CommandButton(this);
-        }
-
-        @Override
-        public @Nullable
-        SessionCommand2 getCommand_impl() {
-            return mCommand;
-        }
-
-        @Override
-        public int getIconResId_impl() {
-            return mIconResId;
-        }
-
-        @Override
-        public @Nullable String getDisplayName_impl() {
-            return mDisplayName;
-        }
-
-        @Override
-        public @Nullable Bundle getExtras_impl() {
-            return mExtras;
-        }
-
-        @Override
-        public boolean isEnabled_impl() {
-            return mEnabled;
-        }
-
-        @NonNull Bundle toBundle() {
-            Bundle bundle = new Bundle();
-            bundle.putBundle(KEY_COMMAND, mCommand.toBundle());
-            bundle.putInt(KEY_ICON_RES_ID, mIconResId);
-            bundle.putString(KEY_DISPLAY_NAME, mDisplayName);
-            bundle.putBundle(KEY_EXTRAS, mExtras);
-            bundle.putBoolean(KEY_ENABLED, mEnabled);
-            return bundle;
-        }
-
-        static @Nullable CommandButton fromBundle(Bundle bundle) {
-            if (bundle == null) {
-                return null;
-            }
-            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));
-            builder.setEnabled(bundle.getBoolean(KEY_ENABLED));
-            try {
-                return builder.build();
-            } catch (IllegalStateException e) {
-                // Malformed or version mismatch. Return null for now.
-                return null;
-            }
-        }
-
-        /**
-         * Builder for {@link CommandButton}.
-         */
-        public static class BuilderImpl implements CommandButtonProvider.BuilderProvider {
-            private final CommandButton.Builder mInstance;
-            private SessionCommand2 mCommand;
-            private int mIconResId;
-            private String mDisplayName;
-            private Bundle mExtras;
-            private boolean mEnabled;
-
-            public BuilderImpl(CommandButton.Builder instance) {
-                mInstance = instance;
-                mEnabled = true;
-            }
-
-            @Override
-            public CommandButton.Builder setCommand_impl(SessionCommand2 command) {
-                mCommand = command;
-                return mInstance;
-            }
-
-            @Override
-            public CommandButton.Builder setIconResId_impl(int resId) {
-                mIconResId = resId;
-                return mInstance;
-            }
-
-            @Override
-            public CommandButton.Builder setDisplayName_impl(String displayName) {
-                mDisplayName = displayName;
-                return mInstance;
-            }
-
-            @Override
-            public CommandButton.Builder setEnabled_impl(boolean enabled) {
-                mEnabled = enabled;
-                return mInstance;
-            }
-
-            @Override
-            public CommandButton.Builder setExtras_impl(Bundle extras) {
-                mExtras = extras;
-                return mInstance;
-            }
-
-            @Override
-            public CommandButton build_impl() {
-                if (mEnabled && mCommand == null) {
-                    throw new IllegalStateException("Enabled button needs Command"
-                            + " for controller to invoke the command");
-                }
-                if (mCommand != null && mCommand.getCommandCode() == COMMAND_CODE_CUSTOM
-                        && (mIconResId == 0 || TextUtils.isEmpty(mDisplayName))) {
-                    throw new IllegalStateException("Custom commands needs icon and"
-                            + " and name to display");
-                }
-                return new CommandButtonImpl(mCommand, mIconResId, mDisplayName, mExtras, mEnabled)
-                        .mInstance;
-            }
-        }
-    }
-
-    public static abstract class BuilderBaseImpl<T extends MediaSession2, C extends SessionCallback>
-            implements BuilderBaseProvider<T, C> {
-        final Context mContext;
-        MediaPlayerBase mPlayer;
-        String mId;
-        Executor mCallbackExecutor;
-        C mCallback;
-        MediaPlaylistAgent mPlaylistAgent;
-        VolumeProvider2 mVolumeProvider;
-        PendingIntent mSessionActivity;
-
-        /**
-         * Constructor.
-         *
-         * @param context a context
-         * @throws IllegalArgumentException if any parameter is null, or the player is a
-         *      {@link MediaSession2} or {@link MediaController2}.
-         */
-        // TODO(jaewan): Also need executor
-        public BuilderBaseImpl(@NonNull Context context) {
-            if (context == null) {
-                throw new IllegalArgumentException("context shouldn't be null");
-            }
-            mContext = context;
-            // Ensure non-null
-            mId = "";
-        }
-
-        @Override
-        public void setPlayer_impl(@NonNull MediaPlayerBase player) {
-            if (player == null) {
-                throw new IllegalArgumentException("player shouldn't be null");
-            }
-            mPlayer = player;
-        }
-
-        @Override
-        public void setPlaylistAgent_impl(@NonNull MediaPlaylistAgent playlistAgent) {
-            if (playlistAgent == null) {
-                throw new IllegalArgumentException("playlistAgent shouldn't be null");
-            }
-            mPlaylistAgent = playlistAgent;
-        }
-
-        @Override
-        public void setVolumeProvider_impl(VolumeProvider2 volumeProvider) {
-            mVolumeProvider = volumeProvider;
-        }
-
-        @Override
-        public void setSessionActivity_impl(PendingIntent pi) {
-            mSessionActivity = pi;
-        }
-
-        @Override
-        public void setId_impl(@NonNull String id) {
-            if (id == null) {
-                throw new IllegalArgumentException("id shouldn't be null");
-            }
-            mId = id;
-        }
-
-        @Override
-        public void setSessionCallback_impl(@NonNull Executor executor, @NonNull C callback) {
-            if (executor == null) {
-                throw new IllegalArgumentException("executor shouldn't be null");
-            }
-            if (callback == null) {
-                throw new IllegalArgumentException("callback shouldn't be null");
-            }
-            mCallbackExecutor = executor;
-            mCallback = callback;
-        }
-
-        @Override
-        public abstract T build_impl();
-    }
-
-    public static class BuilderImpl extends BuilderBaseImpl<MediaSession2, SessionCallback> {
-        public BuilderImpl(Context context, Builder instance) {
-            super(context);
-        }
-
-        @Override
-        public MediaSession2 build_impl() {
-            if (mCallbackExecutor == null) {
-                mCallbackExecutor = mContext.getMainExecutor();
-            }
-            if (mCallback == null) {
-                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
deleted file mode 100644
index 53a5986..0000000
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ /dev/null
@@ -1,888 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.media.MediaController2;
-import android.media.MediaItem2;
-import android.media.MediaMetadata2;
-import android.media.MediaSession2.CommandButton;
-import android.media.MediaSession2.ControllerInfo;
-import android.media.Rating2;
-import android.media.SessionCommand2;
-import android.media.SessionCommandGroup2;
-import android.media.VolumeProvider2;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.DeadObjectException;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-
-import androidx.annotation.GuardedBy;
-import androidx.annotation.NonNull;
-
-import com.android.media.MediaSession2Impl.CommandButtonImpl;
-import com.android.media.MediaSession2Impl.CommandGroupImpl;
-import com.android.media.MediaSession2Impl.ControllerInfoImpl;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-public class MediaSession2Stub extends IMediaSession2.Stub {
-
-    static final String ARGUMENT_KEY_POSITION = "android.media.media_session2.key_position";
-    static final String ARGUMENT_KEY_ITEM_INDEX = "android.media.media_session2.key_item_index";
-    static final String ARGUMENT_KEY_PLAYLIST_PARAMS =
-            "android.media.media_session2.key_playlist_params";
-
-    private static final String TAG = "MediaSession2Stub";
-    private static final boolean DEBUG = true; // TODO(jaewan): Rename.
-
-    private static final SparseArray<SessionCommand2> sCommandsForOnCommandRequest =
-            new SparseArray<>();
-
-    private final Object mLock = new Object();
-    private final WeakReference<MediaSession2Impl> mSession;
-
-    @GuardedBy("mLock")
-    private final ArrayMap<IBinder, ControllerInfo> mControllers = new ArrayMap<>();
-    @GuardedBy("mLock")
-    private final Set<IBinder> mConnectingControllers = new HashSet<>();
-    @GuardedBy("mLock")
-    private final ArrayMap<ControllerInfo, SessionCommandGroup2> mAllowedCommandGroupMap =
-            new ArrayMap<>();
-    @GuardedBy("mLock")
-    private final ArrayMap<ControllerInfo, Set<String>> mSubscriptions = new ArrayMap<>();
-
-    public MediaSession2Stub(MediaSession2Impl session) {
-        mSession = new WeakReference<>(session);
-
-        synchronized (sCommandsForOnCommandRequest) {
-            if (sCommandsForOnCommandRequest.size() == 0) {
-                CommandGroupImpl group = new CommandGroupImpl();
-                group.addAllPlaybackCommands();
-                group.addAllPlaylistCommands();
-                Set<SessionCommand2> commands = group.getCommands();
-                for (SessionCommand2 command : commands) {
-                    sCommandsForOnCommandRequest.append(command.getCommandCode(), command);
-                }
-            }
-        }
-    }
-
-    public void destroyNotLocked() {
-        final List<ControllerInfo> list;
-        synchronized (mLock) {
-            mSession.clear();
-            list = getControllers();
-            mControllers.clear();
-        }
-        for (int i = 0; i < list.size(); i++) {
-            IMediaController2 controllerBinder =
-                    ((ControllerInfoImpl) list.get(i).getProvider()).getControllerBinder();
-            try {
-                // Should be used without a lock hold to prevent potential deadlock.
-                controllerBinder.onDisconnected();
-            } catch (RemoteException e) {
-                // Controller is gone. Should be fine because we're destroying.
-            }
-        }
-    }
-
-    private MediaSession2Impl getSession() {
-        final MediaSession2Impl session = mSession.get();
-        if (session == null && DEBUG) {
-            Log.d(TAG, "Session is closed", new IllegalStateException());
-        }
-        return session;
-    }
-
-    // Get controller if the command from caller to session is able to be handled.
-    private ControllerInfo getControllerIfAble(IMediaController2 caller) {
-        synchronized (mLock) {
-            final ControllerInfo controllerInfo = mControllers.get(caller.asBinder());
-            if (controllerInfo == null && DEBUG) {
-                Log.d(TAG, "Controller is disconnected", new IllegalStateException());
-            }
-            return controllerInfo;
-        }
-    }
-
-    // Get controller if the command from caller to session is able to be handled.
-    private ControllerInfo getControllerIfAble(IMediaController2 caller, int commandCode) {
-        synchronized (mLock) {
-            final ControllerInfo controllerInfo = getControllerIfAble(caller);
-            if (controllerInfo == null) {
-                return null;
-            }
-            SessionCommandGroup2 allowedCommands = mAllowedCommandGroupMap.get(controllerInfo);
-            if (allowedCommands == null) {
-                Log.w(TAG, "Controller with null allowed commands. Ignoring",
-                        new IllegalStateException());
-                return null;
-            }
-            if (!allowedCommands.hasCommand(commandCode)) {
-                if (DEBUG) {
-                    Log.d(TAG, "Controller isn't allowed for command " + commandCode);
-                }
-                return null;
-            }
-            return controllerInfo;
-        }
-    }
-
-    // Get controller if the command from caller to session is able to be handled.
-    private ControllerInfo getControllerIfAble(IMediaController2 caller, SessionCommand2 command) {
-        synchronized (mLock) {
-            final ControllerInfo controllerInfo = getControllerIfAble(caller);
-            if (controllerInfo == null) {
-                return null;
-            }
-            SessionCommandGroup2 allowedCommands = mAllowedCommandGroupMap.get(controllerInfo);
-            if (allowedCommands == null) {
-                Log.w(TAG, "Controller with null allowed commands. Ignoring",
-                        new IllegalStateException());
-                return null;
-            }
-            if (!allowedCommands.hasCommand(command)) {
-                if (DEBUG) {
-                    Log.d(TAG, "Controller isn't allowed for command " + command);
-                }
-                return null;
-            }
-            return controllerInfo;
-        }
-    }
-
-    // Return binder if the session is able to send a command to the controller.
-    private IMediaController2 getControllerBinderIfAble(ControllerInfo controller) {
-        if (getSession() == null) {
-            // getSession() already logged if session is closed.
-            return null;
-        }
-        final ControllerInfoImpl impl = ControllerInfoImpl.from(controller);
-        synchronized (mLock) {
-            if (mControllers.get(impl.getId()) != null
-                    || mConnectingControllers.contains(impl.getId())) {
-                return impl.getControllerBinder();
-            }
-            if (DEBUG) {
-                Log.d(TAG, controller + " isn't connected nor connecting",
-                        new IllegalArgumentException());
-            }
-            return null;
-        }
-    }
-
-    // Return binder if the session is able to send a command to the controller.
-    private IMediaController2 getControllerBinderIfAble(ControllerInfo controller,
-            int commandCode) {
-        synchronized (mLock) {
-            SessionCommandGroup2 allowedCommands = mAllowedCommandGroupMap.get(controller);
-            if (allowedCommands == null) {
-                Log.w(TAG, "Controller with null allowed commands. Ignoring");
-                return null;
-            }
-            if (!allowedCommands.hasCommand(commandCode)) {
-                if (DEBUG) {
-                    Log.d(TAG, "Controller isn't allowed for command " + commandCode);
-                }
-                return null;
-            }
-            return getControllerBinderIfAble(controller);
-        }
-    }
-
-    private void onCommand(@NonNull IMediaController2 caller, int commandCode,
-            @NonNull SessionRunnable runnable) {
-        final MediaSession2Impl session = getSession();
-        final ControllerInfo controller = getControllerIfAble(caller, commandCode);
-        if (session == null || controller == null) {
-            return;
-        }
-        session.getCallbackExecutor().execute(() -> {
-            if (getControllerIfAble(caller, commandCode) == null) {
-                return;
-            }
-            SessionCommand2 command = sCommandsForOnCommandRequest.get(commandCode);
-            if (command != null) {
-                boolean accepted = session.getCallback().onCommandRequest(session.getInstance(),
-                        controller, command);
-                if (!accepted) {
-                    // Don't run rejected command.
-                    if (DEBUG) {
-                        Log.d(TAG, "Command (code=" + commandCode + ") from "
-                                + controller + " was rejected by " + session);
-                    }
-                    return;
-                }
-            }
-            runnable.run(session, controller);
-        });
-    }
-
-    private void notifyAll(int commandCode, @NonNull NotifyRunnable runnable) {
-        List<ControllerInfo> controllers = getControllers();
-        for (int i = 0; i < controllers.size(); i++) {
-            notifyInternal(controllers.get(i),
-                    getControllerBinderIfAble(controllers.get(i), commandCode), runnable);
-        }
-    }
-
-    private void notifyAll(@NonNull NotifyRunnable runnable) {
-        List<ControllerInfo> controllers = getControllers();
-        for (int i = 0; i < controllers.size(); i++) {
-            notifyInternal(controllers.get(i),
-                    getControllerBinderIfAble(controllers.get(i)), runnable);
-        }
-    }
-
-    private void notify(@NonNull ControllerInfo controller, @NonNull NotifyRunnable runnable) {
-        notifyInternal(controller, getControllerBinderIfAble(controller), runnable);
-    }
-
-    private void notify(@NonNull ControllerInfo controller, int commandCode,
-            @NonNull NotifyRunnable runnable) {
-        notifyInternal(controller, getControllerBinderIfAble(controller, commandCode), runnable);
-    }
-
-    // Do not call this API directly. Use notify() instead.
-    private void notifyInternal(@NonNull ControllerInfo controller,
-            @NonNull IMediaController2 iController, @NonNull NotifyRunnable runnable) {
-        if (controller == null || iController == null) {
-            return;
-        }
-        try {
-            runnable.run(controller, iController);
-        } catch (DeadObjectException e) {
-            if (DEBUG) {
-                Log.d(TAG, controller.toString() + " is gone", e);
-            }
-            onControllerClosed(iController);
-        } catch (RemoteException e) {
-            // Currently it's TransactionTooLargeException or DeadSystemException.
-            // We'd better to leave log for those cases because
-            //   - TransactionTooLargeException means that we may need to fix our code.
-            //     (e.g. add pagination or special way to deliver Bitmap)
-            //   - DeadSystemException means that errors around it can be ignored.
-            Log.w(TAG, "Exception in " + controller.toString(), e);
-        }
-    }
-
-    private void onControllerClosed(IMediaController2 iController) {
-        ControllerInfo controller;
-        synchronized (mLock) {
-            controller = mControllers.remove(iController.asBinder());
-            if (DEBUG) {
-                Log.d(TAG, "releasing " + controller);
-            }
-            mSubscriptions.remove(controller);
-        }
-        final MediaSession2Impl session = getSession();
-        if (session == null || controller == null) {
-            return;
-        }
-        session.getCallbackExecutor().execute(() -> {
-            session.getCallback().onDisconnected(session.getInstance(), controller);
-        });
-    }
-
-    //////////////////////////////////////////////////////////////////////////////////////////////
-    // AIDL methods for session overrides
-    //////////////////////////////////////////////////////////////////////////////////////////////
-    @Override
-    public void connect(final IMediaController2 caller, final String callingPackage)
-            throws RuntimeException {
-        final MediaSession2Impl session = getSession();
-        if (session == null) {
-            return;
-        }
-        final Context context = session.getContext();
-        final ControllerInfo controllerInfo = new ControllerInfo(context,
-                Binder.getCallingUid(), Binder.getCallingPid(), callingPackage, caller);
-        session.getCallbackExecutor().execute(() -> {
-            if (getSession() == null) {
-                return;
-            }
-            synchronized (mLock) {
-                // Keep connecting controllers.
-                // This helps sessions to call APIs in the onConnect() (e.g. setCustomLayout())
-                // instead of pending them.
-                mConnectingControllers.add(ControllerInfoImpl.from(controllerInfo).getId());
-            }
-            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
-            // media keys to.
-            boolean accept = allowedCommands != null || controllerInfo.isTrusted();
-            if (accept) {
-                ControllerInfoImpl controllerImpl = ControllerInfoImpl.from(controllerInfo);
-                if (DEBUG) {
-                    Log.d(TAG, "Accepting connection, controllerInfo=" + controllerInfo
-                            + " allowedCommands=" + allowedCommands);
-                }
-                if (allowedCommands == null) {
-                    // For trusted apps, send non-null allowed commands to keep connection.
-                    allowedCommands = new SessionCommandGroup2();
-                }
-                synchronized (mLock) {
-                    mConnectingControllers.remove(controllerImpl.getId());
-                    mControllers.put(controllerImpl.getId(),  controllerInfo);
-                    mAllowedCommandGroupMap.put(controllerInfo, allowedCommands);
-                }
-                // If connection is accepted, notify the current state to the controller.
-                // It's needed because we cannot call synchronous calls between session/controller.
-                // Note: We're doing this after the onConnectionChanged(), but there's no guarantee
-                //       that events here are notified after the onConnected() because
-                //       IMediaController2 is oneway (i.e. async call) and Stub will
-                //       use thread poll for incoming calls.
-                final int playerState = session.getInstance().getPlayerState();
-                final long positionEventTimeMs = System.currentTimeMillis();
-                final long positionMs = session.getInstance().getCurrentPosition();
-                final float playbackSpeed = session.getInstance().getPlaybackSpeed();
-                final long bufferedPositionMs = session.getInstance().getBufferedPosition();
-                final Bundle playbackInfoBundle = ((MediaController2Impl.PlaybackInfoImpl)
-                        session.getPlaybackInfo().getProvider()).toBundle();
-                final int repeatMode = session.getInstance().getRepeatMode();
-                final int shuffleMode = session.getInstance().getShuffleMode();
-                final PendingIntent sessionActivity = session.getSessionActivity();
-                final List<MediaItem2> playlist =
-                        allowedCommands.hasCommand(SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST)
-                                ? session.getInstance().getPlaylist() : null;
-                final List<Bundle> playlistBundle;
-                if (playlist != null) {
-                    playlistBundle = new ArrayList<>();
-                    // TODO(jaewan): Find a way to avoid concurrent modification exception.
-                    for (int i = 0; i < playlist.size(); i++) {
-                        final MediaItem2 item = playlist.get(i);
-                        if (item != null) {
-                            final Bundle itemBundle = item.toBundle();
-                            if (itemBundle != null) {
-                                playlistBundle.add(itemBundle);
-                            }
-                        }
-                    }
-                } else {
-                    playlistBundle = null;
-                }
-
-                // Double check if session is still there, because close() can be called in another
-                // thread.
-                if (getSession() == null) {
-                    return;
-                }
-                try {
-                    caller.onConnected(MediaSession2Stub.this, allowedCommands.toBundle(),
-                            playerState, positionEventTimeMs, positionMs, playbackSpeed,
-                            bufferedPositionMs, playbackInfoBundle, repeatMode, shuffleMode,
-                            playlistBundle, sessionActivity);
-                } catch (RemoteException e) {
-                    // Controller may be died prematurely.
-                    // TODO(jaewan): Handle here.
-                }
-            } else {
-                synchronized (mLock) {
-                    mConnectingControllers.remove(ControllerInfoImpl.from(controllerInfo).getId());
-                }
-                if (DEBUG) {
-                    Log.d(TAG, "Rejecting connection, controllerInfo=" + controllerInfo);
-                }
-                try {
-                    caller.onDisconnected();
-                } catch (RemoteException e) {
-                    // Controller may be died prematurely.
-                    // Not an issue because we'll ignore it anyway.
-                }
-            }
-        });
-    }
-
-    @Override
-    public void release(final IMediaController2 caller) throws RemoteException {
-        onControllerClosed(caller);
-    }
-
-    @Override
-    public void setVolumeTo(final IMediaController2 caller, final int value, final int flags)
-            throws RuntimeException {
-        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, 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
-    public void sendTransportControlCommand(IMediaController2 caller,
-            int commandCode, Bundle args) throws RuntimeException {
-        onCommand(caller, commandCode, (session, controller) -> {
-            switch (commandCode) {
-                case SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY:
-                    session.getInstance().play();
-                    break;
-                case SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE:
-                    session.getInstance().pause();
-                    break;
-                case SessionCommand2.COMMAND_CODE_PLAYBACK_STOP:
-                    session.getInstance().stop();
-                    break;
-                case SessionCommand2.COMMAND_CODE_PLAYBACK_PREPARE:
-                    session.getInstance().prepare();
-                    break;
-                case SessionCommand2.COMMAND_CODE_PLAYBACK_SEEK_TO:
-                    session.getInstance().seekTo(args.getLong(ARGUMENT_KEY_POSITION));
-                    break;
-                default:
-                    // TODO(jaewan): Resend unknown (new) commands through the custom command.
-            }
-        });
-    }
-
-    @Override
-    public void sendCustomCommand(final IMediaController2 caller, final Bundle commandBundle,
-            final Bundle args, final ResultReceiver receiver) {
-        final MediaSession2Impl session = getSession();
-        if (session == null) {
-            return;
-        }
-        final SessionCommand2 command = SessionCommand2.fromBundle(commandBundle);
-        if (command == null) {
-            Log.w(TAG, "sendCustomCommand(): Ignoring null command from "
-                    + getControllerIfAble(caller));
-            return;
-        }
-        final ControllerInfo controller = getControllerIfAble(caller, command);
-        if (controller == null) {
-            return;
-        }
-        session.getCallbackExecutor().execute(() -> {
-            if (getControllerIfAble(caller, command) == null) {
-                return;
-            }
-            session.getCallback().onCustomCommand(session.getInstance(),
-                    controller, command, args, receiver);
-        });
-    }
-
-    @Override
-    public void prepareFromUri(final IMediaController2 caller, final Uri uri,
-            final Bundle 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, 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, SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID,
-                (session, controller) -> {
-            if (mediaId == null) {
-                Log.w(TAG, "prepareFromMediaId(): Ignoring null mediaId from " + controller);
-                return;
-            }
-            session.getCallback().onPrepareFromMediaId(session.getInstance(),
-                    controller, mediaId, extras);
-        });
-    }
-
-    @Override
-    public void playFromUri(final IMediaController2 caller, final Uri uri,
-            final Bundle 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, 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, 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, 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, SessionCommand2.COMMAND_CODE_PLAYLIST_SET_LIST, (session, controller) -> {
-            if (playlist == null) {
-                Log.w(TAG, "setPlaylist(): Ignoring null playlist from " + controller);
-                return;
-            }
-            List<MediaItem2> list = new ArrayList<>();
-            for (int i = 0; i < playlist.size(); i++) {
-                // Recreates UUID in the playlist
-                MediaItem2 item = MediaItem2Impl.fromBundle(playlist.get(i), null);
-                if (item != null) {
-                    list.add(item);
-                }
-            }
-            session.getInstance().setPlaylist(list, MediaMetadata2.fromBundle(metadata));
-        });
-    }
-
-    @Override
-    public void updatePlaylistMetadata(final IMediaController2 caller, final Bundle metadata) {
-        onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SET_LIST_METADATA,
-                (session, controller) -> {
-            session.getInstance().updatePlaylistMetadata(MediaMetadata2.fromBundle(metadata));
-        });
-    }
-
-    @Override
-    public void addPlaylistItem(IMediaController2 caller, int index, Bundle mediaItem) {
-        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, SessionCommand2.COMMAND_CODE_PLAYLIST_REMOVE_ITEM,
-                (session, controller) -> {
-            MediaItem2 item = MediaItem2.fromBundle(mediaItem);
-            // Note: MediaItem2 has hidden UUID to identify it across the processes.
-            session.getInstance().removePlaylistItem(item);
-        });
-    }
-
-    @Override
-    public void replacePlaylistItem(IMediaController2 caller, int index, Bundle mediaItem) {
-        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(mediaItem, null));
-                });
-    }
-
-    @Override
-    public void skipToPlaylistItem(IMediaController2 caller, Bundle mediaItem) {
-        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(mediaItem));
-                });
-    }
-
-    @Override
-    public void skipToPreviousItem(IMediaController2 caller) {
-        onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SKIP_PREV_ITEM,
-                (session, controller) -> {
-                    session.getInstance().skipToPreviousItem();
-                });
-    }
-
-    @Override
-    public void skipToNextItem(IMediaController2 caller) {
-        onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SKIP_NEXT_ITEM,
-                (session, controller) -> {
-                    session.getInstance().skipToNextItem();
-                });
-    }
-
-    @Override
-    public void setRepeatMode(IMediaController2 caller, int repeatMode) {
-        onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE,
-                (session, controller) -> {
-                    session.getInstance().setRepeatMode(repeatMode);
-                });
-    }
-
-    @Override
-    public void setShuffleMode(IMediaController2 caller, int shuffleMode) {
-        onCommand(caller, SessionCommand2.COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE,
-                (session, controller) -> {
-                    session.getInstance().setShuffleMode(shuffleMode);
-                });
-    }
-
-    //////////////////////////////////////////////////////////////////////////////////////////////
-    // APIs for MediaSession2Impl
-    //////////////////////////////////////////////////////////////////////////////////////////////
-
-    // TODO(jaewan): (Can be Post-P) Need a way to get controller with permissions
-    public List<ControllerInfo> getControllers() {
-        ArrayList<ControllerInfo> controllers = new ArrayList<>();
-        synchronized (mLock) {
-            for (int i = 0; i < mControllers.size(); i++) {
-                controllers.add(mControllers.valueAt(i));
-            }
-        }
-        return controllers;
-    }
-
-    // Should be used without a lock to prevent potential deadlock.
-    public void notifyPlayerStateChangedNotLocked(int state) {
-        notifyAll((controller, iController) -> {
-            iController.onPlayerStateChanged(state);
-        });
-    }
-
-    // TODO(jaewan): Rename
-    public void notifyPositionChangedNotLocked(long eventTimeMs, long positionMs) {
-        notifyAll((controller, iController) -> {
-            iController.onPositionChanged(eventTimeMs, positionMs);
-        });
-    }
-
-    public void notifyPlaybackSpeedChangedNotLocked(float speed) {
-        notifyAll((controller, iController) -> {
-            iController.onPlaybackSpeedChanged(speed);
-        });
-    }
-
-    public void notifyBufferedPositionChangedNotLocked(long bufferedPositionMs) {
-        notifyAll((controller, iController) -> {
-            iController.onBufferedPositionChanged(bufferedPositionMs);
-        });
-    }
-
-    public void notifyCustomLayoutNotLocked(ControllerInfo controller, List<CommandButton> layout) {
-        notify(controller, (unused, iController) -> {
-            List<Bundle> layoutBundles = new ArrayList<>();
-            for (int i = 0; i < layout.size(); i++) {
-                Bundle bundle = ((CommandButtonImpl) layout.get(i).getProvider()).toBundle();
-                if (bundle != null) {
-                    layoutBundles.add(bundle);
-                }
-            }
-            iController.onCustomLayoutChanged(layoutBundles);
-        });
-    }
-
-    public void notifyPlaylistChangedNotLocked(List<MediaItem2> playlist, MediaMetadata2 metadata) {
-        final List<Bundle> bundleList;
-        if (playlist != null) {
-            bundleList = new ArrayList<>();
-            for (int i = 0; i < playlist.size(); i++) {
-                if (playlist.get(i) != null) {
-                    Bundle bundle = playlist.get(i).toBundle();
-                    if (bundle != null) {
-                        bundleList.add(bundle);
-                    }
-                }
-            }
-        } else {
-            bundleList = null;
-        }
-        final Bundle metadataBundle = (metadata == null) ? null : metadata.toBundle();
-        notifyAll((controller, iController) -> {
-            if (getControllerBinderIfAble(controller,
-                    SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST) != null) {
-                iController.onPlaylistChanged(bundleList, metadataBundle);
-            } else if (getControllerBinderIfAble(controller,
-                    SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST_METADATA) != null) {
-                iController.onPlaylistMetadataChanged(metadataBundle);
-            }
-        });
-    }
-
-    public void notifyPlaylistMetadataChangedNotLocked(MediaMetadata2 metadata) {
-        final Bundle metadataBundle = (metadata == null) ? null : metadata.toBundle();
-        notifyAll(SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST_METADATA,
-                (unused, iController) -> {
-                    iController.onPlaylistMetadataChanged(metadataBundle);
-                });
-    }
-
-    public void notifyRepeatModeChangedNotLocked(int repeatMode) {
-        notifyAll((unused, iController) -> {
-            iController.onRepeatModeChanged(repeatMode);
-        });
-    }
-
-    public void notifyShuffleModeChangedNotLocked(int shuffleMode) {
-        notifyAll((unused, iController) -> {
-            iController.onShuffleModeChanged(shuffleMode);
-        });
-    }
-
-    public void notifyPlaybackInfoChanged(MediaController2.PlaybackInfo playbackInfo) {
-        final Bundle playbackInfoBundle =
-                ((MediaController2Impl.PlaybackInfoImpl) playbackInfo.getProvider()).toBundle();
-        notifyAll((unused, iController) -> {
-            iController.onPlaybackInfoChanged(playbackInfoBundle);
-        });
-    }
-
-    public void setAllowedCommands(ControllerInfo controller, SessionCommandGroup2 commands) {
-        synchronized (mLock) {
-            mAllowedCommandGroupMap.put(controller, commands);
-        }
-        notify(controller, (unused, iController) -> {
-            iController.onAllowedCommandsChanged(commands.toBundle());
-        });
-    }
-
-    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"
-                    + " specified");
-        }
-        if (command == null) {
-            throw new IllegalArgumentException("command shouldn't be null");
-        }
-        notify(controller, (unused, iController) -> {
-            Bundle commandBundle = command.toBundle();
-            iController.onCustomCommand(commandBundle, args, null);
-        });
-    }
-
-    public void sendCustomCommand(SessionCommand2 command, Bundle args) {
-        if (command == null) {
-            throw new IllegalArgumentException("command shouldn't be null");
-        }
-        Bundle commandBundle = command.toBundle();
-        notifyAll((unused, iController) -> {
-            iController.onCustomCommand(commandBundle, args, null);
-        });
-    }
-
-    public void notifyError(int errorCode, Bundle extras) {
-        notifyAll((unused, iController) -> {
-            iController.onError(errorCode, extras);
-        });
-    }
-
-    //////////////////////////////////////////////////////////////////////////////////////////////
-    // Misc
-    //////////////////////////////////////////////////////////////////////////////////////////////
-
-    @FunctionalInterface
-    private interface SessionRunnable {
-        void run(final MediaSession2Impl session, final ControllerInfo controller);
-    }
-
-    @FunctionalInterface
-    private interface NotifyRunnable {
-        void run(final ControllerInfo controller,
-                final IMediaController2 iController) throws RemoteException;
-    }
-}
diff --git a/packages/MediaComponents/src/com/android/media/Rating2Impl.java b/packages/MediaComponents/src/com/android/media/Rating2Impl.java
deleted file mode 100644
index e2b9f0a..0000000
--- a/packages/MediaComponents/src/com/android/media/Rating2Impl.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media;
-
-import static android.media.Rating2.*;
-
-import android.media.Rating2;
-import android.media.Rating2.Style;
-import android.media.update.Rating2Provider;
-import android.os.Bundle;
-import android.util.Log;
-
-import java.util.Objects;
-
-public final class Rating2Impl implements Rating2Provider {
-    private static final String TAG = "Rating2";
-
-    private static final String KEY_STYLE = "android.media.rating2.style";
-    private static final String KEY_VALUE = "android.media.rating2.value";
-
-    private final static float RATING_NOT_RATED = -1.0f;
-
-    private final Rating2 mInstance;
-    private final int mRatingStyle;
-    private final float mRatingValue;
-
-    private Rating2Impl(@Style int ratingStyle, float rating) {
-        mRatingStyle = ratingStyle;
-        mRatingValue = rating;
-        mInstance = new Rating2(this);
-    }
-
-    @Override
-    public String toString_impl() {
-        return "Rating2:style=" + mRatingStyle + " rating="
-                + (mRatingValue < 0.0f ? "unrated" : String.valueOf(mRatingValue));
-    }
-
-    @Override
-    public boolean equals_impl(Object obj) {
-        if (!(obj instanceof Rating2)) {
-            return false;
-        }
-        Rating2Impl other = (Rating2Impl) ((Rating2) obj).getProvider();
-        return mRatingStyle == other.mRatingStyle
-                && mRatingValue == other.mRatingValue;
-    }
-
-    @Override
-    public int hashCode_impl() {
-        return Objects.hash(mRatingStyle, mRatingValue);
-    }
-
-    Rating2 getInstance() {
-        return mInstance;
-    }
-
-    public static Rating2 fromBundle_impl(Bundle bundle) {
-        if (bundle == null) {
-            return null;
-        }
-        return new Rating2Impl(bundle.getInt(KEY_STYLE), bundle.getFloat(KEY_VALUE)).getInstance();
-    }
-
-    public Bundle toBundle_impl() {
-        Bundle bundle = new Bundle();
-        bundle.putInt(KEY_STYLE, mRatingStyle);
-        bundle.putFloat(KEY_VALUE, mRatingValue);
-        return bundle;
-    }
-
-    public static Rating2 newUnratedRating_impl(@Style int ratingStyle) {
-        switch(ratingStyle) {
-            case RATING_HEART:
-            case RATING_THUMB_UP_DOWN:
-            case RATING_3_STARS:
-            case RATING_4_STARS:
-            case RATING_5_STARS:
-            case RATING_PERCENTAGE:
-                return new Rating2Impl(ratingStyle, RATING_NOT_RATED).getInstance();
-            default:
-                return null;
-        }
-    }
-
-    public static Rating2 newHeartRating_impl(boolean hasHeart) {
-        return new Rating2Impl(RATING_HEART, hasHeart ? 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_impl(int starRatingStyle, float starRating) {
-        float maxRating = RATING_NOT_RATED;
-        switch(starRatingStyle) {
-            case RATING_3_STARS:
-                maxRating = 3.0f;
-                break;
-            case RATING_4_STARS:
-                maxRating = 4.0f;
-                break;
-            case RATING_5_STARS:
-                maxRating = 5.0f;
-                break;
-            default:
-                Log.e(TAG, "Invalid rating style (" + starRatingStyle + ") for a star rating");
-                return null;
-        }
-        if ((starRating < 0.0f) || (starRating > maxRating)) {
-            Log.e(TAG, "Trying to set out of range star-based rating");
-            return null;
-        }
-        return new Rating2Impl(starRatingStyle, starRating).getInstance();
-    }
-
-    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(RATING_PERCENTAGE, percent).getInstance();
-        }
-    }
-
-    @Override
-    public boolean isRated_impl() {
-        return mRatingValue >= 0.0f;
-    }
-
-    @Override
-    public int getRatingStyle_impl() {
-        return mRatingStyle;
-    }
-
-    @Override
-    public boolean hasHeart_impl() {
-        if (mRatingStyle != RATING_HEART) {
-            return false;
-        } else {
-            return (mRatingValue == 1.0f);
-        }
-    }
-
-    @Override
-    public boolean isThumbUp_impl() {
-        if (mRatingStyle != RATING_THUMB_UP_DOWN) {
-            return false;
-        } else {
-            return (mRatingValue == 1.0f);
-        }
-    }
-
-    @Override
-    public float getStarRating_impl() {
-        switch (mRatingStyle) {
-            case RATING_3_STARS:
-            case RATING_4_STARS:
-            case RATING_5_STARS:
-                if (mInstance.isRated()) {
-                    return mRatingValue;
-                }
-            default:
-                return -1.0f;
-        }
-    }
-
-    @Override
-    public float getPercentRating_impl() {
-        if ((mRatingStyle != RATING_PERCENTAGE) || !mInstance.isRated()) {
-            return -1.0f;
-        } else {
-            return mRatingValue;
-        }
-    }
-}
diff --git a/packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java b/packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java
deleted file mode 100644
index 1c570aa..0000000
--- a/packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.media.DataSourceDesc;
-import android.media.MediaItem2;
-import android.media.MediaMetadata2;
-import android.media.MediaPlayerBase;
-import android.media.MediaPlayerBase.PlayerEventCallback;
-import android.media.MediaPlaylistAgent;
-import android.media.MediaSession2.OnDataSourceMissingHelper;
-import android.util.ArrayMap;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ThreadLocalRandom;
-
-public class SessionPlaylistAgent extends MediaPlaylistAgent {
-    private static final String TAG = "SessionPlaylistAgent";
-    @VisibleForTesting
-    static final int END_OF_PLAYLIST = -1;
-    @VisibleForTesting
-    static final int NO_VALID_ITEMS = -2;
-
-    private final PlayItem mEopPlayItem = new PlayItem(END_OF_PLAYLIST, null);
-
-    private final Object mLock = new Object();
-    private final MediaSession2Impl mSessionImpl;
-    private final MyPlayerEventCallback mPlayerCallback;
-
-    @GuardedBy("mLock")
-    private MediaPlayerBase mPlayer;
-    @GuardedBy("mLock")
-    private OnDataSourceMissingHelper mDsmHelper;
-    // TODO: Check if having the same item is okay (b/74090741)
-    @GuardedBy("mLock")
-    private ArrayList<MediaItem2> mPlaylist = new ArrayList<>();
-    @GuardedBy("mLock")
-    private ArrayList<MediaItem2> mShuffledList = new ArrayList<>();
-    @GuardedBy("mLock")
-    private Map<MediaItem2, DataSourceDesc> mItemDsdMap = new ArrayMap<>();
-    @GuardedBy("mLock")
-    private MediaMetadata2 mMetadata;
-    @GuardedBy("mLock")
-    private int mRepeatMode;
-    @GuardedBy("mLock")
-    private int mShuffleMode;
-    @GuardedBy("mLock")
-    private PlayItem mCurrent;
-
-    // Called on session callback executor.
-    private class MyPlayerEventCallback extends PlayerEventCallback {
-        public void onCurrentDataSourceChanged(@NonNull MediaPlayerBase mpb,
-                @Nullable DataSourceDesc dsd) {
-            if (mPlayer != mpb) {
-                return;
-            }
-            synchronized (mLock) {
-                if (dsd == null && mCurrent != null) {
-                    mCurrent = getNextValidPlayItemLocked(mCurrent.shuffledIdx, 1);
-                    updateCurrentIfNeededLocked();
-                }
-            }
-        }
-    }
-
-    private class PlayItem {
-        int shuffledIdx;
-        DataSourceDesc dsd;
-        MediaItem2 mediaItem;
-
-        PlayItem(int shuffledIdx) {
-            this(shuffledIdx, null);
-        }
-
-        PlayItem(int shuffledIdx, DataSourceDesc dsd) {
-            this.shuffledIdx = shuffledIdx;
-            if (shuffledIdx >= 0) {
-                this.mediaItem = mShuffledList.get(shuffledIdx);
-                if (dsd == null) {
-                    synchronized (mLock) {
-                        this.dsd = retrieveDataSourceDescLocked(this.mediaItem);
-                    }
-                } else {
-                    this.dsd = dsd;
-                }
-            }
-        }
-
-        boolean isValid() {
-            if (this == mEopPlayItem) {
-                return true;
-            }
-            if (mediaItem == null) {
-                return false;
-            }
-            if (dsd == null) {
-                return false;
-            }
-            if (shuffledIdx >= mShuffledList.size()) {
-                return false;
-            }
-            if (mediaItem != mShuffledList.get(shuffledIdx)) {
-                return false;
-            }
-            if (mediaItem.getDataSourceDesc() != null
-                    && !mediaItem.getDataSourceDesc().equals(dsd)) {
-                return false;
-            }
-            return true;
-        }
-    }
-
-    public SessionPlaylistAgent(@NonNull MediaSession2Impl sessionImpl,
-            @NonNull MediaPlayerBase player) {
-        if (sessionImpl == null) {
-            throw new IllegalArgumentException("sessionImpl shouldn't be null");
-        }
-        if (player == null) {
-            throw new IllegalArgumentException("player shouldn't be null");
-        }
-        mSessionImpl = sessionImpl;
-        mPlayer = player;
-        mPlayerCallback = new MyPlayerEventCallback();
-        mPlayer.registerPlayerEventCallback(mSessionImpl.getCallbackExecutor(), mPlayerCallback);
-    }
-
-    public void setPlayer(@NonNull MediaPlayerBase player) {
-        if (player == null) {
-            throw new IllegalArgumentException("player shouldn't be null");
-        }
-        synchronized (mLock) {
-            if (player == mPlayer) {
-                return;
-            }
-            mPlayer.unregisterPlayerEventCallback(mPlayerCallback);
-            mPlayer = player;
-            mPlayer.registerPlayerEventCallback(
-                    mSessionImpl.getCallbackExecutor(), mPlayerCallback);
-            updatePlayerDataSourceLocked();
-        }
-    }
-
-    public void setOnDataSourceMissingHelper(OnDataSourceMissingHelper helper) {
-        synchronized (mLock) {
-            mDsmHelper = helper;
-        }
-    }
-
-    public void clearOnDataSourceMissingHelper() {
-        synchronized (mLock) {
-            mDsmHelper = null;
-        }
-    }
-
-    @Override
-    public @Nullable List<MediaItem2> getPlaylist() {
-        synchronized (mLock) {
-            return Collections.unmodifiableList(mPlaylist);
-        }
-    }
-
-    @Override
-    public void setPlaylist(@NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) {
-        if (list == null) {
-            throw new IllegalArgumentException("list shouldn't be null");
-        }
-
-        synchronized (mLock) {
-            mItemDsdMap.clear();
-
-            mPlaylist.clear();
-            mPlaylist.addAll(list);
-            applyShuffleModeLocked();
-
-            mMetadata = metadata;
-            mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1);
-            updatePlayerDataSourceLocked();
-        }
-        notifyPlaylistChanged();
-    }
-
-    @Override
-    public @Nullable MediaMetadata2 getPlaylistMetadata() {
-        return mMetadata;
-    }
-
-    @Override
-    public void updatePlaylistMetadata(@Nullable MediaMetadata2 metadata) {
-        synchronized (mLock) {
-            if (metadata == mMetadata) {
-                return;
-            }
-            mMetadata = metadata;
-        }
-        notifyPlaylistMetadataChanged();
-    }
-
-    @Override
-    public void addPlaylistItem(int index, @NonNull MediaItem2 item) {
-        if (item == null) {
-            throw new IllegalArgumentException("item shouldn't be null");
-        }
-        synchronized (mLock) {
-            index = clamp(index, mPlaylist.size());
-            int shuffledIdx = index;
-            mPlaylist.add(index, item);
-            if (mShuffleMode == MediaPlaylistAgent.SHUFFLE_MODE_NONE) {
-                mShuffledList.add(index, item);
-            } else {
-                // Add the item in random position of mShuffledList.
-                shuffledIdx = ThreadLocalRandom.current().nextInt(mShuffledList.size() + 1);
-                mShuffledList.add(shuffledIdx, item);
-            }
-            if (!hasValidItem()) {
-                mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1);
-                updatePlayerDataSourceLocked();
-            } else {
-                updateCurrentIfNeededLocked();
-            }
-        }
-        notifyPlaylistChanged();
-    }
-
-    @Override
-    public void removePlaylistItem(@NonNull MediaItem2 item) {
-        if (item == null) {
-            throw new IllegalArgumentException("item shouldn't be null");
-        }
-        synchronized (mLock) {
-            if (!mPlaylist.remove(item)) {
-                return;
-            }
-            mShuffledList.remove(item);
-            mItemDsdMap.remove(item);
-            updateCurrentIfNeededLocked();
-        }
-        notifyPlaylistChanged();
-    }
-
-    @Override
-    public void replacePlaylistItem(int index, @NonNull MediaItem2 item) {
-        if (item == null) {
-            throw new IllegalArgumentException("item shouldn't be null");
-        }
-        synchronized (mLock) {
-            if (mPlaylist.size() <= 0) {
-                return;
-            }
-            index = clamp(index, mPlaylist.size() - 1);
-            int shuffledIdx = mShuffledList.indexOf(mPlaylist.get(index));
-            mItemDsdMap.remove(mShuffledList.get(shuffledIdx));
-            mShuffledList.set(shuffledIdx, item);
-            mPlaylist.set(index, item);
-            if (!hasValidItem()) {
-                mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1);
-                updatePlayerDataSourceLocked();
-            } else {
-                updateCurrentIfNeededLocked();
-            }
-        }
-        notifyPlaylistChanged();
-    }
-
-    @Override
-    public void skipToPlaylistItem(@NonNull MediaItem2 item) {
-        if (item == null) {
-            throw new IllegalArgumentException("item shouldn't be null");
-        }
-        synchronized (mLock) {
-            if (!hasValidItem() || item.equals(mCurrent.mediaItem)) {
-                return;
-            }
-            int shuffledIdx = mShuffledList.indexOf(item);
-            if (shuffledIdx < 0) {
-                return;
-            }
-            mCurrent = new PlayItem(shuffledIdx);
-            updateCurrentIfNeededLocked();
-        }
-    }
-
-    @Override
-    public void skipToPreviousItem() {
-        synchronized (mLock) {
-            if (!hasValidItem()) {
-                return;
-            }
-            PlayItem prev = getNextValidPlayItemLocked(mCurrent.shuffledIdx, -1);
-            if (prev != mEopPlayItem) {
-                mCurrent = prev;
-            }
-            updateCurrentIfNeededLocked();
-       }
-    }
-
-    @Override
-    public void skipToNextItem() {
-        synchronized (mLock) {
-            if (!hasValidItem() || mCurrent == mEopPlayItem) {
-                return;
-            }
-            PlayItem next = getNextValidPlayItemLocked(mCurrent.shuffledIdx, 1);
-            if (next != mEopPlayItem) {
-                mCurrent = next;
-            }
-            updateCurrentIfNeededLocked();
-        }
-    }
-
-    @Override
-    public int getRepeatMode() {
-        return mRepeatMode;
-    }
-
-    @Override
-    public void setRepeatMode(int repeatMode) {
-        if (repeatMode < MediaPlaylistAgent.REPEAT_MODE_NONE
-                || repeatMode > MediaPlaylistAgent.REPEAT_MODE_GROUP) {
-            return;
-        }
-        synchronized (mLock) {
-            if (mRepeatMode == repeatMode) {
-                return;
-            }
-            mRepeatMode = repeatMode;
-            switch (repeatMode) {
-                case MediaPlaylistAgent.REPEAT_MODE_ONE:
-                    if (mCurrent != null && mCurrent != mEopPlayItem) {
-                        mPlayer.loopCurrent(true);
-                    }
-                    break;
-                case MediaPlaylistAgent.REPEAT_MODE_ALL:
-                case MediaPlaylistAgent.REPEAT_MODE_GROUP:
-                    if (mCurrent == mEopPlayItem) {
-                        mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1);
-                        updatePlayerDataSourceLocked();
-                    }
-                    // pass through
-                case MediaPlaylistAgent.REPEAT_MODE_NONE:
-                    mPlayer.loopCurrent(false);
-                    break;
-            }
-        }
-        notifyRepeatModeChanged();
-    }
-
-    @Override
-    public int getShuffleMode() {
-        return mShuffleMode;
-    }
-
-    @Override
-    public void setShuffleMode(int shuffleMode) {
-        if (shuffleMode < MediaPlaylistAgent.SHUFFLE_MODE_NONE
-                || shuffleMode > MediaPlaylistAgent.SHUFFLE_MODE_GROUP) {
-            return;
-        }
-        synchronized (mLock) {
-            if (mShuffleMode == shuffleMode) {
-                return;
-            }
-            mShuffleMode = shuffleMode;
-            applyShuffleModeLocked();
-            updateCurrentIfNeededLocked();
-        }
-        notifyShuffleModeChanged();
-    }
-
-    @VisibleForTesting
-    int getCurShuffledIndex() {
-        return hasValidItem() ? mCurrent.shuffledIdx : NO_VALID_ITEMS;
-    }
-
-    private boolean hasValidItem() {
-        return mCurrent != null;
-    }
-
-    private DataSourceDesc retrieveDataSourceDescLocked(MediaItem2 item) {
-        DataSourceDesc dsd = item.getDataSourceDesc();
-        if (dsd != null) {
-            mItemDsdMap.put(item, dsd);
-            return dsd;
-        }
-        dsd = mItemDsdMap.get(item);
-        if (dsd != null) {
-            return dsd;
-        }
-        OnDataSourceMissingHelper helper = mDsmHelper;
-        if (helper != null) {
-            // TODO: Do not call onDataSourceMissing with the lock (b/74090741).
-            dsd = helper.onDataSourceMissing(mSessionImpl.getInstance(), item);
-            if (dsd != null) {
-                mItemDsdMap.put(item, dsd);
-            }
-        }
-        return dsd;
-    }
-
-    // TODO: consider to call updateCurrentIfNeededLocked inside (b/74090741)
-    private PlayItem getNextValidPlayItemLocked(int curShuffledIdx, int direction) {
-        int size = mPlaylist.size();
-        if (curShuffledIdx == END_OF_PLAYLIST) {
-            curShuffledIdx = (direction > 0) ? -1 : size;
-        }
-        for (int i = 0; i < size; i++) {
-            curShuffledIdx += direction;
-            if (curShuffledIdx < 0 || curShuffledIdx >= mPlaylist.size()) {
-                if (mRepeatMode == REPEAT_MODE_NONE) {
-                    return (i == size - 1) ? null : mEopPlayItem;
-                } else {
-                    curShuffledIdx = curShuffledIdx < 0 ? mPlaylist.size() - 1 : 0;
-                }
-            }
-            DataSourceDesc dsd = retrieveDataSourceDescLocked(mShuffledList.get(curShuffledIdx));
-            if (dsd != null) {
-                return new PlayItem(curShuffledIdx, dsd);
-            }
-        }
-        return null;
-    }
-
-    private void updateCurrentIfNeededLocked() {
-        if (!hasValidItem() || mCurrent.isValid()) {
-            return;
-        }
-        int shuffledIdx = mShuffledList.indexOf(mCurrent.mediaItem);
-        if (shuffledIdx >= 0) {
-            // Added an item.
-            mCurrent.shuffledIdx = shuffledIdx;
-            return;
-        }
-
-        if (mCurrent.shuffledIdx >= mShuffledList.size()) {
-            mCurrent = getNextValidPlayItemLocked(mShuffledList.size() - 1, 1);
-        } else {
-            mCurrent.mediaItem = mShuffledList.get(mCurrent.shuffledIdx);
-            if (retrieveDataSourceDescLocked(mCurrent.mediaItem) == null) {
-                mCurrent = getNextValidPlayItemLocked(mCurrent.shuffledIdx, 1);
-            }
-        }
-        updatePlayerDataSourceLocked();
-        return;
-    }
-
-    private void updatePlayerDataSourceLocked() {
-        if (mCurrent == null || mCurrent == mEopPlayItem) {
-            return;
-        }
-        if (mPlayer.getCurrentDataSource() != mCurrent.dsd) {
-            mPlayer.setDataSource(mCurrent.dsd);
-            mPlayer.loopCurrent(mRepeatMode == MediaPlaylistAgent.REPEAT_MODE_ONE);
-        }
-        // TODO: Call setNextDataSource (b/74090741)
-    }
-
-    private void applyShuffleModeLocked() {
-        mShuffledList.clear();
-        mShuffledList.addAll(mPlaylist);
-        if (mShuffleMode == MediaPlaylistAgent.SHUFFLE_MODE_ALL
-                || mShuffleMode == MediaPlaylistAgent.SHUFFLE_MODE_GROUP) {
-            Collections.shuffle(mShuffledList);
-        }
-    }
-
-    // Clamps value to [0, size]
-    private static int clamp(int value, int size) {
-        if (value < 0) {
-            return 0;
-        }
-        return (value > size) ? size : value;
-    }
-}
diff --git a/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java b/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
deleted file mode 100644
index 396ebbb..0000000
--- a/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media;
-
-import static android.media.SessionToken2.TYPE_LIBRARY_SERVICE;
-import static android.media.SessionToken2.TYPE_SESSION;
-import static android.media.SessionToken2.TYPE_SESSION_SERVICE;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.media.SessionToken2;
-import android.media.SessionToken2.TokenType;
-import android.media.update.SessionToken2Provider;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.text.TextUtils;
-
-import java.util.List;
-
-public class SessionToken2Impl implements SessionToken2Provider {
-    private static final String KEY_UID = "android.media.token.uid";
-    private static final String KEY_TYPE = "android.media.token.type";
-    private static final String KEY_PACKAGE_NAME = "android.media.token.package_name";
-    private static final String KEY_SERVICE_NAME = "android.media.token.service_name";
-    private static final String KEY_ID = "android.media.token.id";
-    private static final String KEY_SESSION_BINDER = "android.media.token.session_binder";
-
-    private final SessionToken2 mInstance;
-    private final int mUid;
-    private final @TokenType int mType;
-    private final String mPackageName;
-    private final String mServiceName;
-    private final String mId;
-    private final IMediaSession2 mSessionBinder;
-
-    /**
-     * Public constructor for the legacy support (i.e. browser can try connecting to any browser
-     * service if it knows the service name)
-     */
-    public SessionToken2Impl(Context context, SessionToken2 instance,
-            String packageName, String serviceName, int uid) {
-        if (TextUtils.isEmpty(packageName)) {
-            throw new IllegalArgumentException("packageName shouldn't be empty");
-        }
-        if (TextUtils.isEmpty(serviceName)) {
-            throw new IllegalArgumentException("serviceName shouldn't be empty");
-        }
-        mInstance = instance;
-        // Calculate uid if it's not specified.
-        final PackageManager manager = context.getPackageManager();
-        if (uid < 0) {
-            try {
-                uid = manager.getPackageUid(packageName, 0);
-            } catch (NameNotFoundException e) {
-                throw new IllegalArgumentException("Cannot find package " + packageName);
-            }
-        }
-        mUid = uid;
-        mId = null;
-        mType = -1;
-        mPackageName = packageName;
-        mServiceName = serviceName;
-        mSessionBinder = null;
-    }
-
-    SessionToken2Impl(int uid, int type, String packageName, String serviceName, String id,
-            IMediaSession2 sessionBinder) {
-        // TODO(jaewan): Add sanity check (b/73863865)
-        mUid = uid;
-        mType = type;
-        mPackageName = packageName;
-        mServiceName = serviceName;
-        mId = id;
-        mSessionBinder = sessionBinder;
-        mInstance = new SessionToken2(this);
-    }
-
-    public static String getSessionId(ResolveInfo resolveInfo) {
-        if (resolveInfo == null || resolveInfo.serviceInfo == null) {
-            return null;
-        } else if (resolveInfo.serviceInfo.metaData == null) {
-            return "";
-        }
-        return null;
-    }
-
-    public SessionToken2 getInstance() {
-        return mInstance;
-    }
-
-    @Override
-    public String getPackageName_impl() {
-        return mPackageName;
-    }
-
-    @Override
-    public int getUid_impl() {
-        return mUid;
-    }
-
-    @Override
-    public String getId_imp() {
-        return mId;
-    }
-
-    @Override
-    public int getType_impl() {
-        return mType;
-    }
-
-    String getServiceName() {
-        return mServiceName;
-    }
-
-    IMediaSession2 getSessionBinder() {
-        return mSessionBinder;
-    }
-
-    public static SessionToken2 fromBundle_impl(Bundle bundle) {
-        if (bundle == null) {
-            return null;
-        }
-        final int uid = bundle.getInt(KEY_UID);
-        final @TokenType int type = bundle.getInt(KEY_TYPE, -1);
-        final String packageName = bundle.getString(KEY_PACKAGE_NAME);
-        final String serviceName = bundle.getString(KEY_SERVICE_NAME);
-        final String id = bundle.getString(KEY_ID);
-        final IBinder sessionBinder = bundle.getBinder(KEY_SESSION_BINDER);
-
-        // Sanity check.
-        switch (type) {
-            case TYPE_SESSION:
-                if (sessionBinder == null) {
-                    throw new IllegalArgumentException("Unexpected sessionBinder for session,"
-                            + " binder=" + sessionBinder);
-                }
-                break;
-            case TYPE_SESSION_SERVICE:
-            case TYPE_LIBRARY_SERVICE:
-                if (TextUtils.isEmpty(serviceName)) {
-                    throw new IllegalArgumentException("Session service needs service name");
-                }
-                break;
-            default:
-                throw new IllegalArgumentException("Invalid type");
-        }
-        if (TextUtils.isEmpty(packageName) || id == null) {
-            throw new IllegalArgumentException("Package name nor ID cannot be null.");
-        }
-        return new SessionToken2Impl(uid, type, packageName, serviceName, id,
-                sessionBinder != null ? IMediaSession2.Stub.asInterface(sessionBinder) : null)
-                .getInstance();
-    }
-
-    @Override
-    public Bundle toBundle_impl() {
-        Bundle bundle = new Bundle();
-        bundle.putInt(KEY_UID, mUid);
-        bundle.putString(KEY_PACKAGE_NAME, mPackageName);
-        bundle.putString(KEY_SERVICE_NAME, mServiceName);
-        bundle.putString(KEY_ID, mId);
-        bundle.putInt(KEY_TYPE, mType);
-        bundle.putBinder(KEY_SESSION_BINDER,
-                mSessionBinder != null ? mSessionBinder.asBinder() : null);
-        return bundle;
-    }
-
-    @Override
-    public int hashCode_impl() {
-        final int prime = 31;
-        return mType
-                + prime * (mUid
-                + prime * (mPackageName.hashCode()
-                + prime * (mId.hashCode()
-                + prime * (mServiceName != null ? mServiceName.hashCode() : 0))));
-    }
-
-    @Override
-    public boolean equals_impl(Object obj) {
-        if (!(obj instanceof SessionToken2)) {
-            return false;
-        }
-        SessionToken2Impl other = from((SessionToken2) obj);
-        return mUid == other.mUid
-                && TextUtils.equals(mPackageName, other.mPackageName)
-                && TextUtils.equals(mServiceName, other.mServiceName)
-                && TextUtils.equals(mId, other.mId)
-                && mType == other.mType;
-    }
-
-    @Override
-    public String toString_impl() {
-        return "SessionToken {pkg=" + mPackageName + " id=" + mId + " type=" + mType
-                + " service=" + mServiceName + " binder=" + mSessionBinder + "}";
-    }
-
-    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
deleted file mode 100644
index bf22e1b..0000000
--- a/packages/MediaComponents/src/com/android/media/VolumeProvider2Impl.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.media;
-
-import static android.media.VolumeProvider2.VOLUME_CONTROL_ABSOLUTE;
-import static android.media.VolumeProvider2.VOLUME_CONTROL_FIXED;
-import static android.media.VolumeProvider2.VOLUME_CONTROL_RELATIVE;
-
-import android.media.VolumeProvider2;
-import android.media.update.VolumeProvider2Provider;
-
-public class VolumeProvider2Impl implements VolumeProvider2Provider {
-    private final VolumeProvider2 mInstance;
-    private final int mControlType;
-    private final int mMaxVolume;
-
-    private int mCurrentVolume;
-    private Callback mCallback;
-
-    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) {
-            throw new IllegalArgumentException("wrong controlType " + controlType);
-        }
-        if (maxVolume < 0 || currentVolume < 0) {
-            throw new IllegalArgumentException("volume shouldn't be negative"
-                    + ", maxVolume=" + maxVolume + ", currentVolume=" + currentVolume);
-        }
-        if (currentVolume > maxVolume) {
-            throw new IllegalArgumentException("currentVolume shouldn't be greater than maxVolume"
-                    + ", maxVolume=" + maxVolume + ", currentVolume=" + currentVolume);
-        }
-        mInstance = instance;
-        mControlType = controlType;
-        mMaxVolume = maxVolume;
-        mCurrentVolume = currentVolume;
-    }
-
-    @Override
-    public int getControlType_impl() {
-        return mControlType;
-    }
-
-    @Override
-    public int getMaxVolume_impl() {
-        return mMaxVolume;
-    }
-
-    @Override
-    public int getCurrentVolume_impl() {
-        return mCurrentVolume;
-    }
-
-    @Override
-    public void setCurrentVolume_impl(int currentVolume) {
-        if (currentVolume < 0) {
-            throw new IllegalArgumentException("currentVolume shouldn't be negative"
-                    + ", currentVolume=" + currentVolume);
-        }
-        mCurrentVolume = currentVolume;
-        if (mCallback != null) {
-            mCallback.onVolumeChanged(mInstance);
-        }
-    }
-
-    /**
-     * Sets a callback to receive volume changes.
-     */
-    public void setCallback(Callback callback) {
-        mCallback = callback;
-    }
-
-    /**
-     * Listens for changes to the volume.
-     */
-    public static abstract class Callback {
-        public abstract void onVolumeChanged(VolumeProvider2 volumeProvider);
-    }
-}
diff --git a/packages/MediaComponents/src/com/android/media/subtitle/MediaTimeProvider.java b/packages/MediaComponents/src/com/android/media/subtitle/MediaTimeProvider.java
deleted file mode 100644
index af36d7f..0000000
--- a/packages/MediaComponents/src/com/android/media/subtitle/MediaTimeProvider.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media.subtitle;
-
-// Note: This is just copied from android.media.MediaTimeProvider.
-public interface MediaTimeProvider {
-    // we do not allow negative media time
-    /**
-     * Presentation time value if no timed event notification is requested.
-     */
-    public final static long NO_TIME = -1;
-
-    /**
-     * Cancels all previous notification request from this listener if any.  It
-     * registers the listener to get seek and stop notifications.  If timeUs is
-     * not negative, it also registers the listener for a timed event
-     * notification when the presentation time reaches (becomes greater) than
-     * the value specified.  This happens immediately if the current media time
-     * is larger than or equal to timeUs.
-     *
-     * @param timeUs presentation time to get timed event callback at (or
-     *               {@link #NO_TIME})
-     */
-    public void notifyAt(long timeUs, OnMediaTimeListener listener);
-
-    /**
-     * Cancels all previous notification request from this listener if any.  It
-     * registers the listener to get seek and stop notifications.  If the media
-     * is stopped, the listener will immediately receive a stop notification.
-     * Otherwise, it will receive a timed event notificaton.
-     */
-    public void scheduleUpdate(OnMediaTimeListener listener);
-
-    /**
-     * Cancels all previous notification request from this listener if any.
-     */
-    public void cancelNotifications(OnMediaTimeListener listener);
-
-    /**
-     * Get the current presentation time.
-     *
-     * @param precise   Whether getting a precise time is important. This is
-     *                  more costly.
-     * @param monotonic Whether returned time should be monotonic: that is,
-     *                  greater than or equal to the last returned time.  Don't
-     *                  always set this to true.  E.g. this has undesired
-     *                  consequences if the media is seeked between calls.
-     * @throws IllegalStateException if the media is not initialized
-     */
-    public long getCurrentTimeUs(boolean precise, boolean monotonic)
-            throws IllegalStateException;
-
-    public static interface OnMediaTimeListener {
-        /**
-         * Called when the registered time was reached naturally.
-         *
-         * @param timeUs current media time
-         */
-        void onTimedEvent(long timeUs);
-
-        /**
-         * Called when the media time changed due to seeking.
-         *
-         * @param timeUs current media time
-         */
-        void onSeek(long timeUs);
-
-        /**
-         * Called when the playback stopped.  This is not called on pause, only
-         * on full stop, at which point there is no further current media time.
-         */
-        void onStop();
-    }
-}
-
diff --git a/packages/MediaComponents/src/com/android/media/subtitle/SubtitleController.java b/packages/MediaComponents/src/com/android/media/subtitle/SubtitleController.java
deleted file mode 100644
index 97d3927..0000000
--- a/packages/MediaComponents/src/com/android/media/subtitle/SubtitleController.java
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media.subtitle;
-
-import android.content.Context;
-import android.media.MediaFormat;
-import android.media.MediaPlayer2.TrackInfo;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.view.accessibility.CaptioningManager;
-
-import com.android.media.subtitle.SubtitleTrack.RenderingWidget;
-
-import java.util.Locale;
-import java.util.Vector;
-
-// Note: This is forked from android.media.SubtitleController since P
-/**
- * The subtitle controller provides the architecture to display subtitles for a
- * media source.  It allows specifying which tracks to display, on which anchor
- * to display them, and also allows adding external, out-of-band subtitle tracks.
- */
-public class SubtitleController {
-    private MediaTimeProvider mTimeProvider;
-    private Vector<Renderer> mRenderers;
-    private Vector<SubtitleTrack> mTracks;
-    private SubtitleTrack mSelectedTrack;
-    private boolean mShowing;
-    private CaptioningManager mCaptioningManager;
-    private Handler mHandler;
-
-    private static final int WHAT_SHOW = 1;
-    private static final int WHAT_HIDE = 2;
-    private static final int WHAT_SELECT_TRACK = 3;
-    private static final int WHAT_SELECT_DEFAULT_TRACK = 4;
-
-    private final Handler.Callback mCallback = new Handler.Callback() {
-        @Override
-        public boolean handleMessage(Message msg) {
-            switch (msg.what) {
-            case WHAT_SHOW:
-                doShow();
-                return true;
-            case WHAT_HIDE:
-                doHide();
-                return true;
-            case WHAT_SELECT_TRACK:
-                doSelectTrack((SubtitleTrack)msg.obj);
-                return true;
-            case WHAT_SELECT_DEFAULT_TRACK:
-                doSelectDefaultTrack();
-                return true;
-            default:
-                return false;
-            }
-        }
-    };
-
-    private CaptioningManager.CaptioningChangeListener mCaptioningChangeListener =
-        new CaptioningManager.CaptioningChangeListener() {
-            @Override
-            public void onEnabledChanged(boolean enabled) {
-                selectDefaultTrack();
-            }
-
-            @Override
-            public void onLocaleChanged(Locale locale) {
-                selectDefaultTrack();
-            }
-        };
-
-    public SubtitleController(Context context) {
-        this(context, null, null);
-    }
-
-    /**
-     * Creates a subtitle controller for a media playback object that implements
-     * the MediaTimeProvider interface.
-     *
-     * @param timeProvider
-     */
-    public SubtitleController(
-            Context context,
-            MediaTimeProvider timeProvider,
-            Listener listener) {
-        mTimeProvider = timeProvider;
-        mListener = listener;
-
-        mRenderers = new Vector<Renderer>();
-        mShowing = false;
-        mTracks = new Vector<SubtitleTrack>();
-        mCaptioningManager =
-            (CaptioningManager)context.getSystemService(Context.CAPTIONING_SERVICE);
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        mCaptioningManager.removeCaptioningChangeListener(
-                mCaptioningChangeListener);
-        super.finalize();
-    }
-
-    /**
-     * @return the available subtitle tracks for this media. These include
-     * the tracks found by {@link MediaPlayer} as well as any tracks added
-     * manually via {@link #addTrack}.
-     */
-    public SubtitleTrack[] getTracks() {
-        synchronized(mTracks) {
-            SubtitleTrack[] tracks = new SubtitleTrack[mTracks.size()];
-            mTracks.toArray(tracks);
-            return tracks;
-        }
-    }
-
-    /**
-     * @return the currently selected subtitle track
-     */
-    public SubtitleTrack getSelectedTrack() {
-        return mSelectedTrack;
-    }
-
-    private RenderingWidget getRenderingWidget() {
-        if (mSelectedTrack == null) {
-            return null;
-        }
-        return mSelectedTrack.getRenderingWidget();
-    }
-
-    /**
-     * Selects a subtitle track.  As a result, this track will receive
-     * in-band data from the {@link MediaPlayer}.  However, this does
-     * not change the subtitle visibility.
-     *
-     * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
-     *
-     * @param track The subtitle track to select.  This must be one of the
-     *              tracks in {@link #getTracks}.
-     * @return true if the track was successfully selected.
-     */
-    public boolean selectTrack(SubtitleTrack track) {
-        if (track != null && !mTracks.contains(track)) {
-            return false;
-        }
-
-        processOnAnchor(mHandler.obtainMessage(WHAT_SELECT_TRACK, track));
-        return true;
-    }
-
-    private void doSelectTrack(SubtitleTrack track) {
-        mTrackIsExplicit = true;
-        if (mSelectedTrack == track) {
-            return;
-        }
-
-        if (mSelectedTrack != null) {
-            mSelectedTrack.hide();
-            mSelectedTrack.setTimeProvider(null);
-        }
-
-        mSelectedTrack = track;
-        if (mAnchor != null) {
-            mAnchor.setSubtitleWidget(getRenderingWidget());
-        }
-
-        if (mSelectedTrack != null) {
-            mSelectedTrack.setTimeProvider(mTimeProvider);
-            mSelectedTrack.show();
-        }
-
-        if (mListener != null) {
-            mListener.onSubtitleTrackSelected(track);
-        }
-    }
-
-    /**
-     * @return the default subtitle track based on system preferences, or null,
-     * if no such track exists in this manager.
-     *
-     * Supports HLS-flags: AUTOSELECT, FORCED & DEFAULT.
-     *
-     * 1. If captioning is disabled, only consider FORCED tracks. Otherwise,
-     * consider all tracks, but prefer non-FORCED ones.
-     * 2. If user selected "Default" caption language:
-     *   a. If there is a considered track with DEFAULT=yes, returns that track
-     *      (favor the first one in the current language if there are more than
-     *      one default tracks, or the first in general if none of them are in
-     *      the current language).
-     *   b. Otherwise, if there is a track with AUTOSELECT=yes in the current
-     *      language, return that one.
-     *   c. If there are no default tracks, and no autoselectable tracks in the
-     *      current language, return null.
-     * 3. If there is a track with the caption language, select that one.  Prefer
-     * the one with AUTOSELECT=no.
-     *
-     * The default values for these flags are DEFAULT=no, AUTOSELECT=yes
-     * and FORCED=no.
-     */
-    public SubtitleTrack getDefaultTrack() {
-        SubtitleTrack bestTrack = null;
-        int bestScore = -1;
-
-        Locale selectedLocale = mCaptioningManager.getLocale();
-        Locale locale = selectedLocale;
-        if (locale == null) {
-            locale = Locale.getDefault();
-        }
-        boolean selectForced = !mCaptioningManager.isEnabled();
-
-        synchronized(mTracks) {
-            for (SubtitleTrack track: mTracks) {
-                MediaFormat format = track.getFormat();
-                String language = format.getString(MediaFormat.KEY_LANGUAGE);
-                boolean forced =
-                    format.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0;
-                boolean autoselect =
-                    format.getInteger(MediaFormat.KEY_IS_AUTOSELECT, 1) != 0;
-                boolean is_default =
-                    format.getInteger(MediaFormat.KEY_IS_DEFAULT, 0) != 0;
-
-                boolean languageMatches =
-                    (locale == null ||
-                    locale.getLanguage().equals("") ||
-                    locale.getISO3Language().equals(language) ||
-                    locale.getLanguage().equals(language));
-                // is_default is meaningless unless caption language is 'default'
-                int score = (forced ? 0 : 8) +
-                    (((selectedLocale == null) && is_default) ? 4 : 0) +
-                    (autoselect ? 0 : 2) + (languageMatches ? 1 : 0);
-
-                if (selectForced && !forced) {
-                    continue;
-                }
-
-                // we treat null locale/language as matching any language
-                if ((selectedLocale == null && is_default) ||
-                    (languageMatches &&
-                     (autoselect || forced || selectedLocale != null))) {
-                    if (score > bestScore) {
-                        bestScore = score;
-                        bestTrack = track;
-                    }
-                }
-            }
-        }
-        return bestTrack;
-    }
-
-    private boolean mTrackIsExplicit = false;
-    private boolean mVisibilityIsExplicit = false;
-
-    /** should be called from anchor thread */
-    public void selectDefaultTrack() {
-        processOnAnchor(mHandler.obtainMessage(WHAT_SELECT_DEFAULT_TRACK));
-    }
-
-    private void doSelectDefaultTrack() {
-        if (mTrackIsExplicit) {
-            // If track selection is explicit, but visibility
-            // is not, it falls back to the captioning setting
-            if (!mVisibilityIsExplicit) {
-                if (mCaptioningManager.isEnabled() ||
-                    (mSelectedTrack != null &&
-                     mSelectedTrack.getFormat().getInteger(
-                            MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0)) {
-                    show();
-                } else if (mSelectedTrack != null
-                        && mSelectedTrack.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
-                    hide();
-                }
-                mVisibilityIsExplicit = false;
-            }
-            return;
-        }
-
-        // We can have a default (forced) track even if captioning
-        // is not enabled.  This is handled by getDefaultTrack().
-        // Show this track unless subtitles were explicitly hidden.
-        SubtitleTrack track = getDefaultTrack();
-        if (track != null) {
-            selectTrack(track);
-            mTrackIsExplicit = false;
-            if (!mVisibilityIsExplicit) {
-                show();
-                mVisibilityIsExplicit = false;
-            }
-        }
-    }
-
-    /** must be called from anchor thread */
-    public void reset() {
-        checkAnchorLooper();
-        hide();
-        selectTrack(null);
-        mTracks.clear();
-        mTrackIsExplicit = false;
-        mVisibilityIsExplicit = false;
-        mCaptioningManager.removeCaptioningChangeListener(
-                mCaptioningChangeListener);
-    }
-
-    /**
-     * Adds a new, external subtitle track to the manager.
-     *
-     * @param format the format of the track that will include at least
-     *               the MIME type {@link MediaFormat@KEY_MIME}.
-     * @return the created {@link SubtitleTrack} object
-     */
-    public SubtitleTrack addTrack(MediaFormat format) {
-        synchronized(mRenderers) {
-            for (Renderer renderer: mRenderers) {
-                if (renderer.supports(format)) {
-                    SubtitleTrack track = renderer.createTrack(format);
-                    if (track != null) {
-                        synchronized(mTracks) {
-                            if (mTracks.size() == 0) {
-                                mCaptioningManager.addCaptioningChangeListener(
-                                        mCaptioningChangeListener);
-                            }
-                            mTracks.add(track);
-                        }
-                        return track;
-                    }
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Show the selected (or default) subtitle track.
-     *
-     * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
-     */
-    public void show() {
-        processOnAnchor(mHandler.obtainMessage(WHAT_SHOW));
-    }
-
-    private void doShow() {
-        mShowing = true;
-        mVisibilityIsExplicit = true;
-        if (mSelectedTrack != null) {
-            mSelectedTrack.show();
-        }
-    }
-
-    /**
-     * Hide the selected (or default) subtitle track.
-     *
-     * Should be called from the anchor's (UI) thread. {@see #Anchor.getSubtitleLooper}
-     */
-    public void hide() {
-        processOnAnchor(mHandler.obtainMessage(WHAT_HIDE));
-    }
-
-    private void doHide() {
-        mVisibilityIsExplicit = true;
-        if (mSelectedTrack != null) {
-            mSelectedTrack.hide();
-        }
-        mShowing = false;
-    }
-
-    /**
-     * Interface for supporting a single or multiple subtitle types in {@link
-     * MediaPlayer}.
-     */
-    public abstract static class Renderer {
-        /**
-         * Called by {@link MediaPlayer}'s {@link SubtitleController} when a new
-         * subtitle track is detected, to see if it should use this object to
-         * parse and display this subtitle track.
-         *
-         * @param format the format of the track that will include at least
-         *               the MIME type {@link MediaFormat@KEY_MIME}.
-         *
-         * @return true if and only if the track format is supported by this
-         * renderer
-         */
-        public abstract boolean supports(MediaFormat format);
-
-        /**
-         * Called by {@link MediaPlayer}'s {@link SubtitleController} for each
-         * subtitle track that was detected and is supported by this object to
-         * create a {@link SubtitleTrack} object.  This object will be created
-         * for each track that was found.  If the track is selected for display,
-         * this object will be used to parse and display the track data.
-         *
-         * @param format the format of the track that will include at least
-         *               the MIME type {@link MediaFormat@KEY_MIME}.
-         * @return a {@link SubtitleTrack} object that will be used to parse
-         * and render the subtitle track.
-         */
-        public abstract SubtitleTrack createTrack(MediaFormat format);
-    }
-
-    /**
-     * Add support for a subtitle format in {@link MediaPlayer}.
-     *
-     * @param renderer a {@link SubtitleController.Renderer} object that adds
-     *                 support for a subtitle format.
-     */
-    public void registerRenderer(Renderer renderer) {
-        synchronized(mRenderers) {
-            // TODO how to get available renderers in the system
-            if (!mRenderers.contains(renderer)) {
-                // TODO should added renderers override existing ones (to allow replacing?)
-                mRenderers.add(renderer);
-            }
-        }
-    }
-
-    public boolean hasRendererFor(MediaFormat format) {
-        synchronized(mRenderers) {
-            // TODO how to get available renderers in the system
-            for (Renderer renderer: mRenderers) {
-                if (renderer.supports(format)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
-
-    /**
-     * Subtitle anchor, an object that is able to display a subtitle renderer,
-     * e.g. a VideoView.
-     */
-    public interface Anchor {
-        /**
-         * Anchor should use the supplied subtitle rendering widget, or
-         * none if it is null.
-         */
-        public void setSubtitleWidget(RenderingWidget subtitleWidget);
-
-        /**
-         * Anchors provide the looper on which all track visibility changes
-         * (track.show/hide, setSubtitleWidget) will take place.
-         */
-        public Looper getSubtitleLooper();
-    }
-
-    private Anchor mAnchor;
-
-    /**
-     *  called from anchor's looper (if any, both when unsetting and
-     *  setting)
-     */
-    public void setAnchor(Anchor anchor) {
-        if (mAnchor == anchor) {
-            return;
-        }
-
-        if (mAnchor != null) {
-            checkAnchorLooper();
-            mAnchor.setSubtitleWidget(null);
-        }
-        mAnchor = anchor;
-        mHandler = null;
-        if (mAnchor != null) {
-            mHandler = new Handler(mAnchor.getSubtitleLooper(), mCallback);
-            checkAnchorLooper();
-            mAnchor.setSubtitleWidget(getRenderingWidget());
-        }
-    }
-
-    private void checkAnchorLooper() {
-        assert mHandler != null : "Should have a looper already";
-        assert Looper.myLooper() == mHandler.getLooper()
-                : "Must be called from the anchor's looper";
-    }
-
-    private void processOnAnchor(Message m) {
-        assert mHandler != null : "Should have a looper already";
-        if (Looper.myLooper() == mHandler.getLooper()) {
-            mHandler.dispatchMessage(m);
-        } else {
-            mHandler.sendMessage(m);
-        }
-    }
-
-    public interface Listener {
-        /**
-         * Called when a subtitle track has been selected.
-         *
-         * @param track selected subtitle track or null
-         */
-        public void onSubtitleTrackSelected(SubtitleTrack track);
-    }
-
-    private Listener mListener;
-}
diff --git a/packages/MediaComponents/src/com/android/media/subtitle/SubtitleTrack.java b/packages/MediaComponents/src/com/android/media/subtitle/SubtitleTrack.java
deleted file mode 100644
index 6b9064a..0000000
--- a/packages/MediaComponents/src/com/android/media/subtitle/SubtitleTrack.java
+++ /dev/null
@@ -1,696 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media.subtitle;
-
-import android.graphics.Canvas;
-import android.media.MediaFormat;
-import android.media.MediaPlayer2.TrackInfo;
-import android.media.SubtitleData;
-import android.os.Handler;
-import android.util.Log;
-import android.util.LongSparseArray;
-import android.util.Pair;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.Vector;
-
-// Note: This is forked from android.media.SubtitleTrack since P
-/**
- * A subtitle track abstract base class that is responsible for parsing and displaying
- * an instance of a particular type of subtitle.
- */
-public abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeListener {
-    private static final String TAG = "SubtitleTrack";
-    private long mLastUpdateTimeMs;
-    private long mLastTimeMs;
-
-    private Runnable mRunnable;
-
-    final private LongSparseArray<Run> mRunsByEndTime = new LongSparseArray<Run>();
-    final private LongSparseArray<Run> mRunsByID = new LongSparseArray<Run>();
-
-    private CueList mCues;
-    final private Vector<Cue> mActiveCues = new Vector<Cue>();
-    protected boolean mVisible;
-
-    public boolean DEBUG = false;
-
-    protected Handler mHandler = new Handler();
-
-    private MediaFormat mFormat;
-
-    public SubtitleTrack(MediaFormat format) {
-        mFormat = format;
-        mCues = new CueList();
-        clearActiveCues();
-        mLastTimeMs = -1;
-    }
-
-    public final MediaFormat getFormat() {
-        return mFormat;
-    }
-
-    private long mNextScheduledTimeMs = -1;
-
-    public void onData(SubtitleData data) {
-        long runID = data.getStartTimeUs() + 1;
-        onData(data.getData(), true /* eos */, runID);
-        setRunDiscardTimeMs(
-                runID,
-                (data.getStartTimeUs() + data.getDurationUs()) / 1000);
-    }
-
-    /**
-     * Called when there is input data for the subtitle track.  The
-     * complete subtitle for a track can include multiple whole units
-     * (runs).  Each of these units can have multiple sections.  The
-     * contents of a run are submitted in sequential order, with eos
-     * indicating the last section of the run.  Calls from different
-     * runs must not be intermixed.
-     *
-     * @param data subtitle data byte buffer
-     * @param eos true if this is the last section of the run.
-     * @param runID mostly-unique ID for this run of data.  Subtitle cues
-     *              with runID of 0 are discarded immediately after
-     *              display.  Cues with runID of ~0 are discarded
-     *              only at the deletion of the track object.  Cues
-     *              with other runID-s are discarded at the end of the
-     *              run, which defaults to the latest timestamp of
-     *              any of its cues (with this runID).
-     */
-    protected abstract void onData(byte[] data, boolean eos, long runID);
-
-    /**
-     * Called when adding the subtitle rendering widget to the view hierarchy,
-     * as well as when showing or hiding the subtitle track, or when the video
-     * surface position has changed.
-     *
-     * @return the widget that renders this subtitle track. For most renderers
-     *         there should be a single shared instance that is used for all
-     *         tracks supported by that renderer, as at most one subtitle track
-     *         is visible at one time.
-     */
-    public abstract RenderingWidget getRenderingWidget();
-
-    /**
-     * Called when the active cues have changed, and the contents of the subtitle
-     * view should be updated.
-     */
-    public abstract void updateView(Vector<Cue> activeCues);
-
-    protected synchronized void updateActiveCues(boolean rebuild, long timeMs) {
-        // out-of-order times mean seeking or new active cues being added
-        // (during their own timespan)
-        if (rebuild || mLastUpdateTimeMs > timeMs) {
-            clearActiveCues();
-        }
-
-        for(Iterator<Pair<Long, Cue> > it =
-                mCues.entriesBetween(mLastUpdateTimeMs, timeMs).iterator(); it.hasNext(); ) {
-            Pair<Long, Cue> event = it.next();
-            Cue cue = event.second;
-
-            if (cue.mEndTimeMs == event.first) {
-                // remove past cues
-                if (DEBUG) Log.v(TAG, "Removing " + cue);
-                mActiveCues.remove(cue);
-                if (cue.mRunID == 0) {
-                    it.remove();
-                }
-            } else if (cue.mStartTimeMs == event.first) {
-                // add new cues
-                // TRICKY: this will happen in start order
-                if (DEBUG) Log.v(TAG, "Adding " + cue);
-                if (cue.mInnerTimesMs != null) {
-                    cue.onTime(timeMs);
-                }
-                mActiveCues.add(cue);
-            } else if (cue.mInnerTimesMs != null) {
-                // cue is modified
-                cue.onTime(timeMs);
-            }
-        }
-
-        /* complete any runs */
-        while (mRunsByEndTime.size() > 0 &&
-               mRunsByEndTime.keyAt(0) <= timeMs) {
-            removeRunsByEndTimeIndex(0); // removes element
-        }
-        mLastUpdateTimeMs = timeMs;
-    }
-
-    private void removeRunsByEndTimeIndex(int ix) {
-        Run run = mRunsByEndTime.valueAt(ix);
-        while (run != null) {
-            Cue cue = run.mFirstCue;
-            while (cue != null) {
-                mCues.remove(cue);
-                Cue nextCue = cue.mNextInRun;
-                cue.mNextInRun = null;
-                cue = nextCue;
-            }
-            mRunsByID.remove(run.mRunID);
-            Run nextRun = run.mNextRunAtEndTimeMs;
-            run.mPrevRunAtEndTimeMs = null;
-            run.mNextRunAtEndTimeMs = null;
-            run = nextRun;
-        }
-        mRunsByEndTime.removeAt(ix);
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        /* remove all cues (untangle all cross-links) */
-        int size = mRunsByEndTime.size();
-        for(int ix = size - 1; ix >= 0; ix--) {
-            removeRunsByEndTimeIndex(ix);
-        }
-
-        super.finalize();
-    }
-
-    private synchronized void takeTime(long timeMs) {
-        mLastTimeMs = timeMs;
-    }
-
-    protected synchronized void clearActiveCues() {
-        if (DEBUG) Log.v(TAG, "Clearing " + mActiveCues.size() + " active cues");
-        mActiveCues.clear();
-        mLastUpdateTimeMs = -1;
-    }
-
-    protected void scheduleTimedEvents() {
-        /* get times for the next event */
-        if (mTimeProvider != null) {
-            mNextScheduledTimeMs = mCues.nextTimeAfter(mLastTimeMs);
-            if (DEBUG) Log.d(TAG, "sched @" + mNextScheduledTimeMs + " after " + mLastTimeMs);
-            mTimeProvider.notifyAt(
-                    mNextScheduledTimeMs >= 0 ?
-                        (mNextScheduledTimeMs * 1000) : MediaTimeProvider.NO_TIME,
-                    this);
-        }
-    }
-
-    @Override
-    public void onTimedEvent(long timeUs) {
-        if (DEBUG) Log.d(TAG, "onTimedEvent " + timeUs);
-        synchronized (this) {
-            long timeMs = timeUs / 1000;
-            updateActiveCues(false, timeMs);
-            takeTime(timeMs);
-        }
-        updateView(mActiveCues);
-        scheduleTimedEvents();
-    }
-
-    @Override
-    public void onSeek(long timeUs) {
-        if (DEBUG) Log.d(TAG, "onSeek " + timeUs);
-        synchronized (this) {
-            long timeMs = timeUs / 1000;
-            updateActiveCues(true, timeMs);
-            takeTime(timeMs);
-        }
-        updateView(mActiveCues);
-        scheduleTimedEvents();
-    }
-
-    @Override
-    public void onStop() {
-        synchronized (this) {
-            if (DEBUG) Log.d(TAG, "onStop");
-            clearActiveCues();
-            mLastTimeMs = -1;
-        }
-        updateView(mActiveCues);
-        mNextScheduledTimeMs = -1;
-        mTimeProvider.notifyAt(MediaTimeProvider.NO_TIME, this);
-    }
-
-    protected MediaTimeProvider mTimeProvider;
-
-    public void show() {
-        if (mVisible) {
-            return;
-        }
-
-        mVisible = true;
-        RenderingWidget renderingWidget = getRenderingWidget();
-        if (renderingWidget != null) {
-            renderingWidget.setVisible(true);
-        }
-        if (mTimeProvider != null) {
-            mTimeProvider.scheduleUpdate(this);
-        }
-    }
-
-    public void hide() {
-        if (!mVisible) {
-            return;
-        }
-
-        if (mTimeProvider != null) {
-            mTimeProvider.cancelNotifications(this);
-        }
-        RenderingWidget renderingWidget = getRenderingWidget();
-        if (renderingWidget != null) {
-            renderingWidget.setVisible(false);
-        }
-        mVisible = false;
-    }
-
-    protected synchronized boolean addCue(Cue cue) {
-        mCues.add(cue);
-
-        if (cue.mRunID != 0) {
-            Run run = mRunsByID.get(cue.mRunID);
-            if (run == null) {
-                run = new Run();
-                mRunsByID.put(cue.mRunID, run);
-                run.mEndTimeMs = cue.mEndTimeMs;
-            } else if (run.mEndTimeMs < cue.mEndTimeMs) {
-                run.mEndTimeMs = cue.mEndTimeMs;
-            }
-
-            // link-up cues in the same run
-            cue.mNextInRun = run.mFirstCue;
-            run.mFirstCue = cue;
-        }
-
-        // if a cue is added that should be visible, need to refresh view
-        long nowMs = -1;
-        if (mTimeProvider != null) {
-            try {
-                nowMs = mTimeProvider.getCurrentTimeUs(
-                        false /* precise */, true /* monotonic */) / 1000;
-            } catch (IllegalStateException e) {
-                // handle as it we are not playing
-            }
-        }
-
-        if (DEBUG) Log.v(TAG, "mVisible=" + mVisible + ", " +
-                cue.mStartTimeMs + " <= " + nowMs + ", " +
-                cue.mEndTimeMs + " >= " + mLastTimeMs);
-
-        if (mVisible &&
-                cue.mStartTimeMs <= nowMs &&
-                // we don't trust nowMs, so check any cue since last callback
-                cue.mEndTimeMs >= mLastTimeMs) {
-            if (mRunnable != null) {
-                mHandler.removeCallbacks(mRunnable);
-            }
-            final SubtitleTrack track = this;
-            final long thenMs = nowMs;
-            mRunnable = new Runnable() {
-                @Override
-                public void run() {
-                    // even with synchronized, it is possible that we are going
-                    // to do multiple updates as the runnable could be already
-                    // running.
-                    synchronized (track) {
-                        mRunnable = null;
-                        updateActiveCues(true, thenMs);
-                        updateView(mActiveCues);
-                    }
-                }
-            };
-            // delay update so we don't update view on every cue.  TODO why 10?
-            if (mHandler.postDelayed(mRunnable, 10 /* delay */)) {
-                if (DEBUG) Log.v(TAG, "scheduling update");
-            } else {
-                if (DEBUG) Log.w(TAG, "failed to schedule subtitle view update");
-            }
-            return true;
-        }
-
-        if (mVisible &&
-                cue.mEndTimeMs >= mLastTimeMs &&
-                (cue.mStartTimeMs < mNextScheduledTimeMs ||
-                 mNextScheduledTimeMs < 0)) {
-            scheduleTimedEvents();
-        }
-
-        return false;
-    }
-
-    public synchronized void setTimeProvider(MediaTimeProvider timeProvider) {
-        if (mTimeProvider == timeProvider) {
-            return;
-        }
-        if (mTimeProvider != null) {
-            mTimeProvider.cancelNotifications(this);
-        }
-        mTimeProvider = timeProvider;
-        if (mTimeProvider != null) {
-            mTimeProvider.scheduleUpdate(this);
-        }
-    }
-
-
-    static class CueList {
-        private static final String TAG = "CueList";
-        // simplistic, inefficient implementation
-        private SortedMap<Long, Vector<Cue> > mCues;
-        public boolean DEBUG = false;
-
-        private boolean addEvent(Cue cue, long timeMs) {
-            Vector<Cue> cues = mCues.get(timeMs);
-            if (cues == null) {
-                cues = new Vector<Cue>(2);
-                mCues.put(timeMs, cues);
-            } else if (cues.contains(cue)) {
-                // do not duplicate cues
-                return false;
-            }
-
-            cues.add(cue);
-            return true;
-        }
-
-        private void removeEvent(Cue cue, long timeMs) {
-            Vector<Cue> cues = mCues.get(timeMs);
-            if (cues != null) {
-                cues.remove(cue);
-                if (cues.size() == 0) {
-                    mCues.remove(timeMs);
-                }
-            }
-        }
-
-        public void add(Cue cue) {
-            // ignore non-positive-duration cues
-            if (cue.mStartTimeMs >= cue.mEndTimeMs)
-                return;
-
-            if (!addEvent(cue, cue.mStartTimeMs)) {
-                return;
-            }
-
-            long lastTimeMs = cue.mStartTimeMs;
-            if (cue.mInnerTimesMs != null) {
-                for (long timeMs: cue.mInnerTimesMs) {
-                    if (timeMs > lastTimeMs && timeMs < cue.mEndTimeMs) {
-                        addEvent(cue, timeMs);
-                        lastTimeMs = timeMs;
-                    }
-                }
-            }
-
-            addEvent(cue, cue.mEndTimeMs);
-        }
-
-        public void remove(Cue cue) {
-            removeEvent(cue, cue.mStartTimeMs);
-            if (cue.mInnerTimesMs != null) {
-                for (long timeMs: cue.mInnerTimesMs) {
-                    removeEvent(cue, timeMs);
-                }
-            }
-            removeEvent(cue, cue.mEndTimeMs);
-        }
-
-        public Iterable<Pair<Long, Cue>> entriesBetween(
-                final long lastTimeMs, final long timeMs) {
-            return new Iterable<Pair<Long, Cue> >() {
-                @Override
-                public Iterator<Pair<Long, Cue> > iterator() {
-                    if (DEBUG) Log.d(TAG, "slice (" + lastTimeMs + ", " + timeMs + "]=");
-                    try {
-                        return new EntryIterator(
-                                mCues.subMap(lastTimeMs + 1, timeMs + 1));
-                    } catch(IllegalArgumentException e) {
-                        return new EntryIterator(null);
-                    }
-                }
-            };
-        }
-
-        public long nextTimeAfter(long timeMs) {
-            SortedMap<Long, Vector<Cue>> tail = null;
-            try {
-                tail = mCues.tailMap(timeMs + 1);
-                if (tail != null) {
-                    return tail.firstKey();
-                } else {
-                    return -1;
-                }
-            } catch(IllegalArgumentException e) {
-                return -1;
-            } catch(NoSuchElementException e) {
-                return -1;
-            }
-        }
-
-        class EntryIterator implements Iterator<Pair<Long, Cue> > {
-            @Override
-            public boolean hasNext() {
-                return !mDone;
-            }
-
-            @Override
-            public Pair<Long, Cue> next() {
-                if (mDone) {
-                    throw new NoSuchElementException("");
-                }
-                mLastEntry = new Pair<Long, Cue>(
-                        mCurrentTimeMs, mListIterator.next());
-                mLastListIterator = mListIterator;
-                if (!mListIterator.hasNext()) {
-                    nextKey();
-                }
-                return mLastEntry;
-            }
-
-            @Override
-            public void remove() {
-                // only allow removing end tags
-                if (mLastListIterator == null ||
-                        mLastEntry.second.mEndTimeMs != mLastEntry.first) {
-                    throw new IllegalStateException("");
-                }
-
-                // remove end-cue
-                mLastListIterator.remove();
-                mLastListIterator = null;
-                if (mCues.get(mLastEntry.first).size() == 0) {
-                    mCues.remove(mLastEntry.first);
-                }
-
-                // remove rest of the cues
-                Cue cue = mLastEntry.second;
-                removeEvent(cue, cue.mStartTimeMs);
-                if (cue.mInnerTimesMs != null) {
-                    for (long timeMs: cue.mInnerTimesMs) {
-                        removeEvent(cue, timeMs);
-                    }
-                }
-            }
-
-            public EntryIterator(SortedMap<Long, Vector<Cue> > cues) {
-                if (DEBUG) Log.v(TAG, cues + "");
-                mRemainingCues = cues;
-                mLastListIterator = null;
-                nextKey();
-            }
-
-            private void nextKey() {
-                do {
-                    try {
-                        if (mRemainingCues == null) {
-                            throw new NoSuchElementException("");
-                        }
-                        mCurrentTimeMs = mRemainingCues.firstKey();
-                        mListIterator =
-                            mRemainingCues.get(mCurrentTimeMs).iterator();
-                        try {
-                            mRemainingCues =
-                                mRemainingCues.tailMap(mCurrentTimeMs + 1);
-                        } catch (IllegalArgumentException e) {
-                            mRemainingCues = null;
-                        }
-                        mDone = false;
-                    } catch (NoSuchElementException e) {
-                        mDone = true;
-                        mRemainingCues = null;
-                        mListIterator = null;
-                        return;
-                    }
-                } while (!mListIterator.hasNext());
-            }
-
-            private long mCurrentTimeMs;
-            private Iterator<Cue> mListIterator;
-            private boolean mDone;
-            private SortedMap<Long, Vector<Cue> > mRemainingCues;
-            private Iterator<Cue> mLastListIterator;
-            private Pair<Long,Cue> mLastEntry;
-        }
-
-        CueList() {
-            mCues = new TreeMap<Long, Vector<Cue>>();
-        }
-    }
-
-    public static class Cue {
-        public long mStartTimeMs;
-        public long mEndTimeMs;
-        public long[] mInnerTimesMs;
-        public long mRunID;
-
-        public Cue mNextInRun;
-
-        public void onTime(long timeMs) { }
-    }
-
-    /** update mRunsByEndTime (with default end time) */
-    protected void finishedRun(long runID) {
-        if (runID != 0 && runID != ~0) {
-            Run run = mRunsByID.get(runID);
-            if (run != null) {
-                run.storeByEndTimeMs(mRunsByEndTime);
-            }
-        }
-    }
-
-    /** update mRunsByEndTime with given end time */
-    public void setRunDiscardTimeMs(long runID, long timeMs) {
-        if (runID != 0 && runID != ~0) {
-            Run run = mRunsByID.get(runID);
-            if (run != null) {
-                run.mEndTimeMs = timeMs;
-                run.storeByEndTimeMs(mRunsByEndTime);
-            }
-        }
-    }
-
-    /** whether this is a text track who fires events instead getting rendered */
-    public int getTrackType() {
-        return getRenderingWidget() == null
-                ? TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT
-                : TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE;
-    }
-
-
-    private static class Run {
-        public Cue mFirstCue;
-        public Run mNextRunAtEndTimeMs;
-        public Run mPrevRunAtEndTimeMs;
-        public long mEndTimeMs = -1;
-        public long mRunID = 0;
-        private long mStoredEndTimeMs = -1;
-
-        public void storeByEndTimeMs(LongSparseArray<Run> runsByEndTime) {
-            // remove old value if any
-            int ix = runsByEndTime.indexOfKey(mStoredEndTimeMs);
-            if (ix >= 0) {
-                if (mPrevRunAtEndTimeMs == null) {
-                    assert(this == runsByEndTime.valueAt(ix));
-                    if (mNextRunAtEndTimeMs == null) {
-                        runsByEndTime.removeAt(ix);
-                    } else {
-                        runsByEndTime.setValueAt(ix, mNextRunAtEndTimeMs);
-                    }
-                }
-                removeAtEndTimeMs();
-            }
-
-            // add new value
-            if (mEndTimeMs >= 0) {
-                mPrevRunAtEndTimeMs = null;
-                mNextRunAtEndTimeMs = runsByEndTime.get(mEndTimeMs);
-                if (mNextRunAtEndTimeMs != null) {
-                    mNextRunAtEndTimeMs.mPrevRunAtEndTimeMs = this;
-                }
-                runsByEndTime.put(mEndTimeMs, this);
-                mStoredEndTimeMs = mEndTimeMs;
-            }
-        }
-
-        public void removeAtEndTimeMs() {
-            Run prev = mPrevRunAtEndTimeMs;
-
-            if (mPrevRunAtEndTimeMs != null) {
-                mPrevRunAtEndTimeMs.mNextRunAtEndTimeMs = mNextRunAtEndTimeMs;
-                mPrevRunAtEndTimeMs = null;
-            }
-            if (mNextRunAtEndTimeMs != null) {
-                mNextRunAtEndTimeMs.mPrevRunAtEndTimeMs = prev;
-                mNextRunAtEndTimeMs = null;
-            }
-        }
-    }
-
-    /**
-     * Interface for rendering subtitles onto a Canvas.
-     */
-    public interface RenderingWidget {
-        /**
-         * Sets the widget's callback, which is used to send updates when the
-         * rendered data has changed.
-         *
-         * @param callback update callback
-         */
-        public void setOnChangedListener(OnChangedListener callback);
-
-        /**
-         * Sets the widget's size.
-         *
-         * @param width width in pixels
-         * @param height height in pixels
-         */
-        public void setSize(int width, int height);
-
-        /**
-         * Sets whether the widget should draw subtitles.
-         *
-         * @param visible true if subtitles should be drawn, false otherwise
-         */
-        public void setVisible(boolean visible);
-
-        /**
-         * Renders subtitles onto a {@link Canvas}.
-         *
-         * @param c canvas on which to render subtitles
-         */
-        public void draw(Canvas c);
-
-        /**
-         * Called when the widget is attached to a window.
-         */
-        public void onAttachedToWindow();
-
-        /**
-         * Called when the widget is detached from a window.
-         */
-        public void onDetachedFromWindow();
-
-        /**
-         * Callback used to send updates about changes to rendering data.
-         */
-        public interface OnChangedListener {
-            /**
-             * Called when the rendering data has changed.
-             *
-             * @param renderingWidget the widget whose data has changed
-             */
-            public void onChanged(RenderingWidget renderingWidget);
-        }
-    }
-}
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
deleted file mode 100644
index 663b813..0000000
--- a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media.update;
-
-import android.app.Notification;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.media.MediaController2;
-import android.media.MediaController2.ControllerCallback;
-import android.media.MediaItem2;
-import android.media.MediaMetadata2;
-import android.media.MediaPlaylistAgent;
-import android.media.MediaSession2;
-import android.media.MediaSession2.ControllerInfo;
-import android.media.MediaSession2.SessionCallback;
-import android.media.Rating2;
-import android.media.SessionCommand2;
-import android.media.SessionCommandGroup2;
-import android.media.SessionToken2;
-import android.media.VolumeProvider2;
-import android.media.update.MediaController2Provider;
-import android.media.update.MediaItem2Provider;
-import android.media.update.MediaMetadata2Provider;
-import android.media.update.MediaPlaylistAgentProvider;
-import android.media.update.MediaSession2Provider;
-import android.media.update.MediaSession2Provider.BuilderBaseProvider;
-import android.media.update.MediaSession2Provider.CommandButtonProvider.BuilderProvider;
-import android.media.update.SessionToken2Provider;
-import android.media.update.StaticProvider;
-import android.media.update.VolumeProvider2Provider;
-import android.os.Bundle;
-import android.os.IInterface;
-
-import com.android.media.IMediaController2;
-import com.android.media.MediaController2Impl;
-import com.android.media.MediaItem2Impl;
-import com.android.media.MediaMetadata2Impl;
-import com.android.media.MediaPlaylistAgentImpl;
-import com.android.media.MediaSession2Impl;
-import com.android.media.Rating2Impl;
-import com.android.media.SessionToken2Impl;
-import com.android.media.VolumeProvider2Impl;
-
-import java.util.concurrent.Executor;
-
-public final class ApiFactory implements StaticProvider {
-    private ApiFactory() { }
-
-    public static StaticProvider initialize(ApplicationInfo updatableInfo) {
-        ApiHelper.initialize(updatableInfo);
-        return new ApiFactory();
-    }
-
-    @Override
-    public MediaController2Provider createMediaController2(
-            Context context, MediaController2 instance, SessionToken2 token,
-            Executor executor, ControllerCallback callback) {
-        return new MediaController2Impl(context, instance, token, executor, callback);
-    }
-
-    @Override
-    public MediaSession2Provider.CommandProvider createMediaSession2Command(
-            SessionCommand2 instance, int commandCode, String action, Bundle extra) {
-        if (action == null && extra == null) {
-            return new MediaSession2Impl.CommandImpl(instance, commandCode);
-        }
-        return new MediaSession2Impl.CommandImpl(instance, action, extra);
-    }
-
-    @Override
-    public SessionCommand2 fromBundle_MediaSession2Command(Bundle command) {
-        return MediaSession2Impl.CommandImpl.fromBundle_impl(command);
-    }
-
-    @Override
-    public MediaSession2Provider.CommandGroupProvider createMediaSession2CommandGroup(
-            SessionCommandGroup2 instance, SessionCommandGroup2 other) {
-        return new MediaSession2Impl.CommandGroupImpl(instance,
-                (other == null) ? null : other.getProvider());
-    }
-
-    @Override
-    public SessionCommandGroup2 fromBundle_MediaSession2CommandGroup(Bundle commands) {
-        return MediaSession2Impl.CommandGroupImpl.fromBundle_impl(commands);
-    }
-
-    @Override
-    public MediaSession2Provider.ControllerInfoProvider createMediaSession2ControllerInfo(
-            Context context, ControllerInfo instance, int uid, int pid, String packageName,
-            IInterface callback) {
-        return new MediaSession2Impl.ControllerInfoImpl(context,
-                instance, uid, pid, packageName, (IMediaController2) callback);
-    }
-
-    @Override
-    public BuilderProvider createMediaSession2CommandButtonBuilder(
-            MediaSession2.CommandButton.Builder instance) {
-        return new MediaSession2Impl.CommandButtonImpl.BuilderImpl(instance);
-    }
-
-    public BuilderBaseProvider<MediaSession2, SessionCallback> createMediaSession2Builder(
-            Context context, MediaSession2.Builder instance) {
-        return new MediaSession2Impl.BuilderImpl(context, instance);
-    }
-
-    @Override
-    public SessionToken2Provider createSessionToken2(Context context, SessionToken2 instance,
-            String packageName, String serviceName, int uid) {
-        return new SessionToken2Impl(context, instance, packageName, serviceName, uid);
-    }
-
-    @Override
-    public SessionToken2 fromBundle_SessionToken2(Bundle bundle) {
-        return SessionToken2Impl.fromBundle_impl(bundle);
-    }
-
-    @Override
-    public MediaItem2Provider.BuilderProvider createMediaItem2Builder(MediaItem2.Builder instance,
-            int flags) {
-        return new MediaItem2Impl.BuilderImpl(instance, flags);
-    }
-
-    @Override
-    public MediaItem2 fromBundle_MediaItem2(Bundle bundle) {
-        return MediaItem2Impl.fromBundle_impl(bundle);
-    }
-
-    @Override
-    public VolumeProvider2Provider createVolumeProvider2(VolumeProvider2 instance, int controlType,
-            int maxVolume, int currentVolume) {
-        return new VolumeProvider2Impl(instance, controlType, maxVolume, currentVolume);
-    }
-
-    @Override
-    public MediaMetadata2 fromBundle_MediaMetadata2(Bundle bundle) {
-        return MediaMetadata2Impl.fromBundle_impl(bundle);
-    }
-
-    @Override
-    public MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
-            MediaMetadata2.Builder instance) {
-        return new MediaMetadata2Impl.BuilderImpl(instance);
-    }
-
-    @Override
-    public MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
-            MediaMetadata2.Builder instance, MediaMetadata2 source) {
-        return new MediaMetadata2Impl.BuilderImpl(instance, source);
-    }
-
-    @Override
-    public Rating2 fromBundle_Rating2(Bundle bundle) {
-        return Rating2Impl.fromBundle_impl(bundle);
-    }
-
-    @Override
-    public Rating2 newUnratedRating_Rating2(int ratingStyle) {
-        return Rating2Impl.newUnratedRating_impl(ratingStyle);
-    }
-
-    @Override
-    public Rating2 newHeartRating_Rating2(boolean hasHeart) {
-        return Rating2Impl.newHeartRating_impl(hasHeart);
-    }
-
-    @Override
-    public Rating2 newThumbRating_Rating2(boolean thumbIsUp) {
-        return Rating2Impl.newThumbRating_impl(thumbIsUp);
-    }
-
-    @Override
-    public Rating2 newStarRating_Rating2(int starRatingStyle, float starRating) {
-        return Rating2Impl.newStarRating_impl(starRatingStyle, starRating);
-    }
-
-    @Override
-    public Rating2 newPercentageRating_Rating2(float percent) {
-        return Rating2Impl.newPercentageRating_impl(percent);
-    }
-
-    @Override
-    public MediaPlaylistAgentProvider createMediaPlaylistAgent(MediaPlaylistAgent instance) {
-        return new MediaPlaylistAgentImpl(instance);
-    }
-}
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiHelper.java b/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
deleted file mode 100644
index f918ed3..0000000
--- a/packages/MediaComponents/src/com/android/media/update/ApiHelper.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media.update;
-
-import android.content.pm.ApplicationInfo;
-
-public final class ApiHelper {
-    private static ApplicationInfo sUpdatableInfo;
-
-    private ApiHelper() { }
-
-    static void initialize(ApplicationInfo updatableInfo) {
-        if (sUpdatableInfo != null) {
-            throw new IllegalStateException("initialize should only be called once");
-        }
-
-        sUpdatableInfo = updatableInfo;
-    }
-}
diff --git a/packages/MediaComponents/src/com/android/widget/SubtitleView.java b/packages/MediaComponents/src/com/android/widget/SubtitleView.java
deleted file mode 100644
index db0ae33..0000000
--- a/packages/MediaComponents/src/com/android/widget/SubtitleView.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.widget;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.os.Looper;
-import android.util.AttributeSet;
-import android.widget.FrameLayout;
-
-import androidx.annotation.Nullable;
-
-import com.android.media.subtitle.SubtitleController.Anchor;
-import com.android.media.subtitle.SubtitleTrack.RenderingWidget;
-
-class SubtitleView extends FrameLayout implements Anchor {
-    private static final String TAG = "SubtitleView";
-
-    private RenderingWidget mSubtitleWidget;
-    private RenderingWidget.OnChangedListener mSubtitlesChangedListener;
-
-    public SubtitleView(Context context) {
-        this(context, null);
-    }
-
-    public SubtitleView(Context context, @Nullable AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SubtitleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public SubtitleView(
-            Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-    }
-
-    @Override
-    public void setSubtitleWidget(RenderingWidget subtitleWidget) {
-        if (mSubtitleWidget == subtitleWidget) {
-            return;
-        }
-
-        final boolean attachedToWindow = isAttachedToWindow();
-        if (mSubtitleWidget != null) {
-            if (attachedToWindow) {
-                mSubtitleWidget.onDetachedFromWindow();
-            }
-
-            mSubtitleWidget.setOnChangedListener(null);
-        }
-        mSubtitleWidget = subtitleWidget;
-
-        if (subtitleWidget != null) {
-            if (mSubtitlesChangedListener == null) {
-                mSubtitlesChangedListener = new RenderingWidget.OnChangedListener() {
-                    @Override
-                    public void onChanged(RenderingWidget renderingWidget) {
-                        invalidate();
-                    }
-                };
-            }
-
-            setWillNotDraw(false);
-            subtitleWidget.setOnChangedListener(mSubtitlesChangedListener);
-
-            if (attachedToWindow) {
-                subtitleWidget.onAttachedToWindow();
-                requestLayout();
-            }
-        } else {
-            setWillNotDraw(true);
-        }
-
-        invalidate();
-    }
-
-    @Override
-    public Looper getSubtitleLooper() {
-        return Looper.getMainLooper();
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        if (mSubtitleWidget != null) {
-            mSubtitleWidget.onAttachedToWindow();
-        }
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        if (mSubtitleWidget != null) {
-            mSubtitleWidget.onDetachedFromWindow();
-        }
-    }
-
-    @Override
-    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-
-        if (mSubtitleWidget != null) {
-            final int width = getWidth() - getPaddingLeft() - getPaddingRight();
-            final int height = getHeight() - getPaddingTop() - getPaddingBottom();
-
-            mSubtitleWidget.setSize(width, height);
-        }
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        super.draw(canvas);
-
-        if (mSubtitleWidget != null) {
-            final int saveCount = canvas.save();
-            canvas.translate(getPaddingLeft(), getPaddingTop());
-            mSubtitleWidget.draw(canvas);
-            canvas.restoreToCount(saveCount);
-        }
-    }
-
-    @Override
-    public CharSequence getAccessibilityClassName() {
-        return SubtitleView.class.getName();
-    }
-}
diff --git a/packages/MediaComponents/src/com/android/widget/VideoViewInterface.java b/packages/MediaComponents/src/com/android/widget/VideoViewInterface.java
deleted file mode 100644
index 854d47e..0000000
--- a/packages/MediaComponents/src/com/android/widget/VideoViewInterface.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.widget;
-
-import android.annotation.NonNull;
-import android.media.MediaPlayer2;
-import android.view.View;
-
-interface VideoViewInterface {
-    /**
-     * Assigns the view's surface to the given MediaPlayer2 instance.
-     *
-     * @param mp MediaPlayer2
-     * @return true if the surface is successfully assigned, false if not. It will fail to assign
-     *         if any of MediaPlayer2 or surface is unavailable.
-     */
-    boolean assignSurfaceToMediaPlayer(MediaPlayer2 mp);
-    void setSurfaceListener(SurfaceListener l);
-    int getViewType();
-    void setMediaPlayer(MediaPlayer2 mp);
-
-    /**
-     * Takes over oldView. It means that the MediaPlayer2 will start rendering on this view.
-     * The visibility of oldView will be set as {@link View.GONE}. If the view doesn't have a
-     * MediaPlayer2 instance or its surface is not available, the actual execution is deferred until
-     * a MediaPlayer2 instance is set by {@link #setMediaPlayer} or its surface becomes available.
-     * {@link SurfaceListener.onSurfaceTakeOverDone} will be called when the actual execution is
-     * done.
-     *
-     * @param oldView The view that MediaPlayer2 is currently rendering on.
-     */
-    void takeOver(@NonNull VideoViewInterface oldView);
-
-    /**
-     * Indicates if the view's surface is available.
-     *
-     * @return true if the surface is available.
-     */
-    boolean hasAvailableSurface();
-
-    /**
-     * An instance of VideoViewInterface calls these surface notification methods accordingly if
-     * a listener has been registered via {@link #setSurfaceListener(SurfaceListener)}.
-     */
-    interface SurfaceListener {
-        void onSurfaceCreated(View view, int width, int height);
-        void onSurfaceDestroyed(View view);
-        void onSurfaceChanged(View view, int width, int height);
-        void onSurfaceTakeOverDone(VideoViewInterface view);
-    }
-}
diff --git a/packages/MediaComponents/tests/Android.mk b/packages/MediaComponents/tests/Android.mk
deleted file mode 100644
index dddfd2a..0000000
--- a/packages/MediaComponents/tests/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    android.test.runner.stubs \
-    android.test.base.stubs \
-    mockito-target-minus-junit4 \
-    junit
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := MediaComponentsTest
-
-LOCAL_INSTRUMENTATION_FOR := MediaComponents
-
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/packages/MediaComponents/tests/AndroidManifest.xml b/packages/MediaComponents/tests/AndroidManifest.xml
deleted file mode 100644
index 7255265..0000000
--- a/packages/MediaComponents/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2018 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.media.tests">
-
-    <application android:label="Media API Test">
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <!--
-    To run the tests use the command:
-    "adb shell am instrument -w com.android.media.tests/android.test.InstrumentationTestRunner"
-    -->
-    <instrumentation
-        android:name="android.test.InstrumentationTestRunner"
-        android:targetPackage="com.android.media.update"
-        android:label="Media API test" />
-
-</manifest>
diff --git a/packages/MediaComponents/tests/src/com/android/media/SessionPlaylistAgentTest.java b/packages/MediaComponents/tests/src/com/android/media/SessionPlaylistAgentTest.java
deleted file mode 100644
index 0807600..0000000
--- a/packages/MediaComponents/tests/src/com/android/media/SessionPlaylistAgentTest.java
+++ /dev/null
@@ -1,643 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media;
-
-import static org.mockito.Mockito.*;
-
-import android.content.Context;
-import android.media.AudioAttributes;
-import android.media.DataSourceDesc;
-import android.media.UriDataSourceDesc;
-import android.media.MediaItem2;
-import android.media.MediaMetadata2;
-import android.media.MediaPlayerBase;
-import android.media.MediaPlayerBase.PlayerEventCallback;
-import android.media.MediaPlaylistAgent;
-import android.media.MediaSession2;
-import android.media.MediaSession2.OnDataSourceMissingHelper;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.test.AndroidTestCase;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Matchers;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/**
- * Tests {@link SessionPlaylistAgent}.
- */
-public class SessionPlaylistAgentTest extends AndroidTestCase {
-    private static final String TAG = "SessionPlaylistAgentTest";
-    private static final int WAIT_TIME_MS = 1000;
-    private static final int INVALID_REPEAT_MODE = -100;
-    private static final int INVALID_SHUFFLE_MODE = -100;
-
-    private Handler mHandler;
-    private Executor mHandlerExecutor;
-
-    private Object mWaitLock = new Object();
-    private Context mContext;
-    private MediaSession2Impl mSessionImpl;
-    private MediaPlayerBase mPlayer;
-    private PlayerEventCallback mPlayerEventCallback;
-    private SessionPlaylistAgent mAgent;
-    private OnDataSourceMissingHelper mDataSourceHelper;
-    private MyPlaylistEventCallback mEventCallback;
-
-    public class MyPlaylistEventCallback extends MediaPlaylistAgent.PlaylistEventCallback {
-        boolean onPlaylistChangedCalled;
-        boolean onPlaylistMetadataChangedCalled;
-        boolean onRepeatModeChangedCalled;
-        boolean onShuffleModeChangedCalled;
-
-        private Object mWaitLock;
-
-        public MyPlaylistEventCallback(Object waitLock) {
-            mWaitLock = waitLock;
-        }
-
-        public void clear() {
-            onPlaylistChangedCalled = false;
-            onPlaylistMetadataChangedCalled = false;
-            onRepeatModeChangedCalled = false;
-            onShuffleModeChangedCalled = false;
-        }
-
-        public void onPlaylistChanged(MediaPlaylistAgent playlistAgent, List<MediaItem2> list,
-                MediaMetadata2 metadata) {
-            synchronized (mWaitLock) {
-                onPlaylistChangedCalled = true;
-                mWaitLock.notify();
-            }
-        }
-
-        public void onPlaylistMetadataChanged(MediaPlaylistAgent playlistAgent,
-                MediaMetadata2 metadata) {
-            synchronized (mWaitLock) {
-                onPlaylistMetadataChangedCalled = true;
-                mWaitLock.notify();
-            }
-        }
-
-        public void onRepeatModeChanged(MediaPlaylistAgent playlistAgent, int repeatMode) {
-            synchronized (mWaitLock) {
-                onRepeatModeChangedCalled = true;
-                mWaitLock.notify();
-            }
-        }
-
-        public void onShuffleModeChanged(MediaPlaylistAgent playlistAgent, int shuffleMode) {
-            synchronized (mWaitLock) {
-                onShuffleModeChangedCalled = true;
-                mWaitLock.notify();
-            }
-        }
-    }
-
-    public class MyDataSourceHelper implements OnDataSourceMissingHelper {
-        @Override
-        public DataSourceDesc onDataSourceMissing(MediaSession2 session, MediaItem2 item) {
-            if (item.getMediaId().contains("WITHOUT_DSD")) {
-                return null;
-            }
-            return new UriDataSourceDesc.Builder()
-                    .setDataSource(getContext(), Uri.parse("dsd://test"))
-                    .setMediaId(item.getMediaId())
-                    .build();
-        }
-    }
-
-    public class MockPlayer extends MediaPlayerBase {
-        @Override
-        public void play() {
-        }
-
-        @Override
-        public void prepare() {
-        }
-
-        @Override
-        public void pause() {
-        }
-
-        @Override
-        public void reset() {
-        }
-
-        @Override
-        public void skipToNext() {
-        }
-
-        @Override
-        public void seekTo(long pos) {
-        }
-
-        @Override
-        public int getPlayerState() {
-            return 0;
-        }
-
-        @Override
-        public int getBufferingState() {
-            return 0;
-        }
-
-        @Override
-        public void setAudioAttributes(AudioAttributes attributes) {
-        }
-
-        @Override
-        public AudioAttributes getAudioAttributes() {
-            return null;
-        }
-
-        @Override
-        public void setDataSource(DataSourceDesc dsd) {
-        }
-
-        @Override
-        public void setNextDataSource(DataSourceDesc dsd) {
-        }
-
-        @Override
-        public void setNextDataSources(List<DataSourceDesc> dsds) {
-        }
-
-        @Override
-        public DataSourceDesc getCurrentDataSource() {
-            return null;
-        }
-
-        @Override
-        public void loopCurrent(boolean loop) {
-        }
-
-        @Override
-        public void setPlaybackSpeed(float speed) {
-        }
-
-        @Override
-        public void setPlayerVolume(float volume) {
-        }
-
-        @Override
-        public float getPlayerVolume() {
-            return 0;
-        }
-
-        @Override
-        public void registerPlayerEventCallback(Executor e, PlayerEventCallback cb) {
-        }
-
-        @Override
-        public void unregisterPlayerEventCallback(PlayerEventCallback cb) {
-        }
-
-        @Override
-        public void close() throws Exception {
-        }
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        mContext = getContext();
-        // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
-        // Dexmaker is used by mockito.
-        System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
-
-        HandlerThread handlerThread = new HandlerThread("SessionPlaylistAgent");
-        handlerThread.start();
-        mHandler = new Handler(handlerThread.getLooper());
-        mHandlerExecutor = (runnable) -> {
-            mHandler.post(runnable);
-        };
-
-        mPlayer = mock(MockPlayer.class);
-        doAnswer(invocation -> {
-            Object[] args = invocation.getArguments();
-            mPlayerEventCallback = (PlayerEventCallback) args[1];
-            return null;
-        }).when(mPlayer).registerPlayerEventCallback(Matchers.any(), Matchers.any());
-
-        mSessionImpl = mock(MediaSession2Impl.class);
-        mDataSourceHelper = new MyDataSourceHelper();
-        mAgent = new SessionPlaylistAgent(mSessionImpl, mPlayer);
-        mAgent.setOnDataSourceMissingHelper(mDataSourceHelper);
-        mEventCallback = new MyPlaylistEventCallback(mWaitLock);
-        mAgent.registerPlaylistEventCallback(mHandlerExecutor, mEventCallback);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        mHandler.getLooper().quitSafely();
-        mHandler = null;
-        mHandlerExecutor = null;
-    }
-
-    @Test
-    public void testSetAndGetShuflleMode() throws Exception {
-        int shuffleMode = mAgent.getShuffleMode();
-        if (shuffleMode != MediaPlaylistAgent.SHUFFLE_MODE_NONE) {
-            mEventCallback.clear();
-            synchronized (mWaitLock) {
-                mAgent.setShuffleMode(MediaPlaylistAgent.SHUFFLE_MODE_NONE);
-                mWaitLock.wait(WAIT_TIME_MS);
-                assertTrue(mEventCallback.onShuffleModeChangedCalled);
-            }
-            assertEquals(MediaPlaylistAgent.SHUFFLE_MODE_NONE, mAgent.getShuffleMode());
-        }
-
-        mEventCallback.clear();
-        synchronized (mWaitLock) {
-            mAgent.setShuffleMode(MediaPlaylistAgent.SHUFFLE_MODE_ALL);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onShuffleModeChangedCalled);
-        }
-        assertEquals(MediaPlaylistAgent.SHUFFLE_MODE_ALL, mAgent.getShuffleMode());
-
-        mEventCallback.clear();
-        synchronized (mWaitLock) {
-            mAgent.setShuffleMode(MediaPlaylistAgent.SHUFFLE_MODE_GROUP);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onShuffleModeChangedCalled);
-        }
-        assertEquals(MediaPlaylistAgent.SHUFFLE_MODE_GROUP, mAgent.getShuffleMode());
-
-        // INVALID_SHUFFLE_MODE will not change the shuffle mode.
-        mEventCallback.clear();
-        synchronized (mWaitLock) {
-            mAgent.setShuffleMode(INVALID_SHUFFLE_MODE);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertFalse(mEventCallback.onShuffleModeChangedCalled);
-        }
-        assertEquals(MediaPlaylistAgent.SHUFFLE_MODE_GROUP, mAgent.getShuffleMode());
-    }
-
-    @Test
-    public void testSetAndGetRepeatMode() throws Exception {
-        int repeatMode = mAgent.getRepeatMode();
-        if (repeatMode != MediaPlaylistAgent.REPEAT_MODE_NONE) {
-            mEventCallback.clear();
-            synchronized (mWaitLock) {
-                mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_NONE);
-                mWaitLock.wait(WAIT_TIME_MS);
-                assertTrue(mEventCallback.onRepeatModeChangedCalled);
-            }
-            assertEquals(MediaPlaylistAgent.REPEAT_MODE_NONE, mAgent.getRepeatMode());
-        }
-
-        mEventCallback.clear();
-        synchronized (mWaitLock) {
-            mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_ONE);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onRepeatModeChangedCalled);
-        }
-        assertEquals(MediaPlaylistAgent.REPEAT_MODE_ONE, mAgent.getRepeatMode());
-
-        mEventCallback.clear();
-        synchronized (mWaitLock) {
-            mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_ALL);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onRepeatModeChangedCalled);
-        }
-        assertEquals(MediaPlaylistAgent.REPEAT_MODE_ALL, mAgent.getRepeatMode());
-
-        mEventCallback.clear();
-        synchronized (mWaitLock) {
-            mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_GROUP);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onRepeatModeChangedCalled);
-        }
-        assertEquals(MediaPlaylistAgent.REPEAT_MODE_GROUP, mAgent.getRepeatMode());
-
-        // INVALID_SHUFFLE_MODE will not change the shuffle mode.
-        mEventCallback.clear();
-        synchronized (mWaitLock) {
-            mAgent.setRepeatMode(INVALID_REPEAT_MODE);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertFalse(mEventCallback.onRepeatModeChangedCalled);
-        }
-        assertEquals(MediaPlaylistAgent.REPEAT_MODE_GROUP, mAgent.getRepeatMode());
-    }
-
-    @Test
-    public void testSetPlaylist() throws Exception {
-        int listSize = 10;
-        createAndSetPlaylist(10);
-        assertEquals(listSize, mAgent.getPlaylist().size());
-        assertEquals(0, mAgent.getCurShuffledIndex());
-    }
-
-    @Test
-    public void testSkipItems() throws Exception {
-        int listSize = 5;
-        List<MediaItem2> playlist = createAndSetPlaylist(listSize);
-
-        mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_NONE);
-        // Test skipToPlaylistItem
-        for (int i = listSize - 1; i >= 0; --i) {
-            mAgent.skipToPlaylistItem(playlist.get(i));
-            assertEquals(i, mAgent.getCurShuffledIndex());
-        }
-
-        // Test skipToNextItem
-        // curPlayPos = 0
-        for (int curPlayPos = 0; curPlayPos < listSize - 1; ++curPlayPos) {
-            mAgent.skipToNextItem();
-            assertEquals(curPlayPos + 1, mAgent.getCurShuffledIndex());
-        }
-        mAgent.skipToNextItem();
-        assertEquals(listSize - 1, mAgent.getCurShuffledIndex());
-
-        // Test skipToPrevious
-        // curPlayPos = listSize - 1
-        for (int curPlayPos = listSize - 1; curPlayPos > 0; --curPlayPos) {
-            mAgent.skipToPreviousItem();
-            assertEquals(curPlayPos - 1, mAgent.getCurShuffledIndex());
-        }
-        mAgent.skipToPreviousItem();
-        assertEquals(0, mAgent.getCurShuffledIndex());
-
-        mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_ALL);
-        // Test skipToPrevious with repeat mode all
-        // curPlayPos = 0
-        mAgent.skipToPreviousItem();
-        assertEquals(listSize - 1, mAgent.getCurShuffledIndex());
-
-        // Test skipToNext with repeat mode all
-        // curPlayPos = listSize - 1
-        mAgent.skipToNextItem();
-        assertEquals(0, mAgent.getCurShuffledIndex());
-
-        mAgent.skipToPreviousItem();
-        // curPlayPos = listSize - 1, nextPlayPos = 0
-        // Test next play pos after setting repeat mode none.
-        mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_NONE);
-        assertEquals(listSize - 1, mAgent.getCurShuffledIndex());
-    }
-
-    @Test
-    public void testEditPlaylist() throws Exception {
-        int listSize = 5;
-        List<MediaItem2> playlist = createAndSetPlaylist(listSize);
-
-        // Test add item: [0 (cur), 1, 2, 3, 4] -> [0 (cur), 1, 5, 2, 3, 4]
-        mEventCallback.clear();
-        MediaItem2 item_5 = generateMediaItem(5);
-        synchronized (mWaitLock) {
-            playlist.add(2, item_5);
-            mAgent.addPlaylistItem(2, item_5);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onPlaylistChangedCalled);
-        }
-        assertPlaylistEquals(playlist, mAgent.getPlaylist());
-
-        mEventCallback.clear();
-        // Move current: [0 (cur), 1, 5, 2, 3, 4] -> [0, 1, 5 (cur), 2, 3, 4]
-        mAgent.skipToPlaylistItem(item_5);
-        // Remove current item: [0, 1, 5 (cur), 2, 3, 4] -> [0, 1, 2 (cur), 3, 4]
-        synchronized (mWaitLock) {
-            playlist.remove(item_5);
-            mAgent.removePlaylistItem(item_5);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onPlaylistChangedCalled);
-        }
-        assertPlaylistEquals(playlist, mAgent.getPlaylist());
-        assertEquals(2, mAgent.getCurShuffledIndex());
-
-        // Remove previous item: [0, 1, 2 (cur), 3, 4] -> [0, 2 (cur), 3, 4]
-        mEventCallback.clear();
-        MediaItem2 previousItem = playlist.get(1);
-        synchronized (mWaitLock) {
-            playlist.remove(previousItem);
-            mAgent.removePlaylistItem(previousItem);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onPlaylistChangedCalled);
-        }
-        assertPlaylistEquals(playlist, mAgent.getPlaylist());
-        assertEquals(1, mAgent.getCurShuffledIndex());
-
-        // Remove next item: [0, 2 (cur), 3, 4] -> [0, 2 (cur), 4]
-        mEventCallback.clear();
-        MediaItem2 nextItem = playlist.get(2);
-        synchronized (mWaitLock) {
-            playlist.remove(nextItem);
-            mAgent.removePlaylistItem(nextItem);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onPlaylistChangedCalled);
-        }
-        assertPlaylistEquals(playlist, mAgent.getPlaylist());
-        assertEquals(1, mAgent.getCurShuffledIndex());
-
-        // Replace item: [0, 2 (cur), 4] -> [0, 2 (cur), 5]
-        mEventCallback.clear();
-        synchronized (mWaitLock) {
-            playlist.set(2, item_5);
-            mAgent.replacePlaylistItem(2, item_5);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onPlaylistChangedCalled);
-        }
-        assertPlaylistEquals(playlist, mAgent.getPlaylist());
-        assertEquals(1, mAgent.getCurShuffledIndex());
-
-        // Move last and remove the last item: [0, 2 (cur), 5] -> [0, 2, 5 (cur)] -> [0, 2 (cur)]
-        MediaItem2 lastItem = playlist.get(1);
-        mAgent.skipToPlaylistItem(lastItem);
-        mEventCallback.clear();
-        synchronized (mWaitLock) {
-            playlist.remove(lastItem);
-            mAgent.removePlaylistItem(lastItem);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onPlaylistChangedCalled);
-        }
-        assertPlaylistEquals(playlist, mAgent.getPlaylist());
-        assertEquals(1, mAgent.getCurShuffledIndex());
-
-        // Remove all items
-        for (int i = playlist.size() - 1; i >= 0; --i) {
-            MediaItem2 item = playlist.get(i);
-            mAgent.skipToPlaylistItem(item);
-            mEventCallback.clear();
-            synchronized (mWaitLock) {
-                playlist.remove(item);
-                mAgent.removePlaylistItem(item);
-                mWaitLock.wait(WAIT_TIME_MS);
-                assertTrue(mEventCallback.onPlaylistChangedCalled);
-            }
-            assertPlaylistEquals(playlist, mAgent.getPlaylist());
-        }
-        assertEquals(SessionPlaylistAgent.NO_VALID_ITEMS, mAgent.getCurShuffledIndex());
-    }
-
-
-    @Test
-    public void testPlaylistWithInvalidItem() throws Exception {
-        int listSize = 2;
-        List<MediaItem2> playlist = createAndSetPlaylist(listSize);
-
-        // Add item: [0 (cur), 1] -> [0 (cur), 3 (no_dsd), 1]
-        mEventCallback.clear();
-        MediaItem2 invalidItem2 = generateMediaItemWithoutDataSourceDesc(2);
-        synchronized (mWaitLock) {
-            playlist.add(1, invalidItem2);
-            mAgent.addPlaylistItem(1, invalidItem2);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onPlaylistChangedCalled);
-        }
-        assertPlaylistEquals(playlist, mAgent.getPlaylist());
-        assertEquals(0, mAgent.getCurShuffledIndex());
-
-        // Test skip to next item:  [0 (cur), 2 (no_dsd), 1] -> [0, 2 (no_dsd), 1 (cur)]
-        mAgent.skipToNextItem();
-        assertEquals(2, mAgent.getCurShuffledIndex());
-
-        // Test skip to previous item: [0, 2 (no_dsd), 1 (cur)] -> [0 (cur), 2 (no_dsd), 1]
-        mAgent.skipToPreviousItem();
-        assertEquals(0, mAgent.getCurShuffledIndex());
-
-        // Remove current item: [0 (cur), 2 (no_dsd), 1] -> [2 (no_dsd), 1 (cur)]
-        mEventCallback.clear();
-        MediaItem2 item = playlist.get(0);
-        synchronized (mWaitLock) {
-            playlist.remove(item);
-            mAgent.removePlaylistItem(item);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onPlaylistChangedCalled);
-        }
-        assertPlaylistEquals(playlist, mAgent.getPlaylist());
-        assertEquals(1, mAgent.getCurShuffledIndex());
-
-        // Remove current item: [2 (no_dsd), 1 (cur)] -> [2 (no_dsd)]
-        mEventCallback.clear();
-        item = playlist.get(1);
-        synchronized (mWaitLock) {
-            playlist.remove(item);
-            mAgent.removePlaylistItem(item);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onPlaylistChangedCalled);
-        }
-        assertPlaylistEquals(playlist, mAgent.getPlaylist());
-        assertEquals(SessionPlaylistAgent.NO_VALID_ITEMS, mAgent.getCurShuffledIndex());
-
-        // Add invalid item: [2 (no_dsd)] -> [0 (no_dsd), 2 (no_dsd)]
-        MediaItem2 invalidItem0 = generateMediaItemWithoutDataSourceDesc(0);
-        mEventCallback.clear();
-        synchronized (mWaitLock) {
-            playlist.add(0, invalidItem0);
-            mAgent.addPlaylistItem(0, invalidItem0);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onPlaylistChangedCalled);
-        }
-        assertPlaylistEquals(playlist, mAgent.getPlaylist());
-        assertEquals(SessionPlaylistAgent.NO_VALID_ITEMS, mAgent.getCurShuffledIndex());
-
-        // Add valid item: [0 (no_dsd), 2 (no_dsd)] -> [0 (no_dsd), 1, 2 (no_dsd)]
-        MediaItem2 invalidItem1 = generateMediaItem(1);
-        mEventCallback.clear();
-        synchronized (mWaitLock) {
-            playlist.add(1, invalidItem1);
-            mAgent.addPlaylistItem(1, invalidItem1);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onPlaylistChangedCalled);
-        }
-        assertPlaylistEquals(playlist, mAgent.getPlaylist());
-        assertEquals(1, mAgent.getCurShuffledIndex());
-
-        // Replace the valid item with an invalid item:
-        // [0 (no_dsd), 1 (cur), 2 (no_dsd)] -> [0 (no_dsd), 3 (no_dsd), 2 (no_dsd)]
-        MediaItem2 invalidItem3 = generateMediaItemWithoutDataSourceDesc(3);
-        mEventCallback.clear();
-        synchronized (mWaitLock) {
-            playlist.set(1, invalidItem3);
-            mAgent.replacePlaylistItem(1, invalidItem3);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onPlaylistChangedCalled);
-        }
-        assertPlaylistEquals(playlist, mAgent.getPlaylist());
-        assertEquals(SessionPlaylistAgent.END_OF_PLAYLIST, mAgent.getCurShuffledIndex());
-    }
-
-    @Test
-    public void testPlaylistAfterOnCurrentDataSourceChanged() throws Exception {
-        int listSize = 2;
-        verify(mPlayer).registerPlayerEventCallback(Matchers.any(), Matchers.any());
-
-        createAndSetPlaylist(listSize);
-        assertEquals(0, mAgent.getCurShuffledIndex());
-
-        mPlayerEventCallback.onCurrentDataSourceChanged(mPlayer, null);
-        assertEquals(1, mAgent.getCurShuffledIndex());
-        mPlayerEventCallback.onCurrentDataSourceChanged(mPlayer, null);
-        assertEquals(SessionPlaylistAgent.END_OF_PLAYLIST, mAgent.getCurShuffledIndex());
-
-        mAgent.skipToNextItem();
-        assertEquals(SessionPlaylistAgent.END_OF_PLAYLIST, mAgent.getCurShuffledIndex());
-
-        mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_ONE);
-        assertEquals(SessionPlaylistAgent.END_OF_PLAYLIST, mAgent.getCurShuffledIndex());
-
-        mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_ALL);
-        assertEquals(0, mAgent.getCurShuffledIndex());
-        mPlayerEventCallback.onCurrentDataSourceChanged(mPlayer, null);
-        assertEquals(1, mAgent.getCurShuffledIndex());
-        mPlayerEventCallback.onCurrentDataSourceChanged(mPlayer, null);
-        assertEquals(0, mAgent.getCurShuffledIndex());
-    }
-
-    private List<MediaItem2> createAndSetPlaylist(int listSize) throws Exception {
-        List<MediaItem2> items = new ArrayList<>();
-        for (int i = 0; i < listSize; ++i) {
-            items.add(generateMediaItem(i));
-        }
-        mEventCallback.clear();
-        synchronized (mWaitLock) {
-            mAgent.setPlaylist(items, null);
-            mWaitLock.wait(WAIT_TIME_MS);
-            assertTrue(mEventCallback.onPlaylistChangedCalled);
-        }
-        return items;
-    }
-
-    private void assertPlaylistEquals(List<MediaItem2> expected, List<MediaItem2> actual) {
-        if (expected == actual) {
-            return;
-        }
-        assertTrue(expected != null && actual != null);
-        assertEquals(expected.size(), actual.size());
-        for (int i = 0; i < expected.size(); ++i) {
-            assertTrue(expected.get(i).equals(actual.get(i)));
-        }
-    }
-
-    private MediaItem2 generateMediaItemWithoutDataSourceDesc(int key) {
-        return new MediaItem2.Builder(0)
-                .setMediaId("TEST_MEDIA_ID_WITHOUT_DSD_" + key)
-                .build();
-    }
-
-    private MediaItem2 generateMediaItem(int key) {
-        return new MediaItem2.Builder(0)
-                .setMediaId("TEST_MEDIA_ID_" + key)
-                .build();
-    }
-}