Remove apex/media - migrated to packages/modules/Media

Fix references for local_include_dirs for aidl support.

BUG: 171106157
Test: Local build and TH
Change-Id: Ice516a0ab0819c4a076c394c05be1643461d4309
diff --git a/Android.bp b/Android.bp
index ee5db70..05175d9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -191,7 +191,6 @@
             "sax/java",
             "telecomm/java",
 
-            "apex/media/aidl/stable",
             // TODO(b/147699819): remove this
             "telephony/java",
         ],
@@ -289,6 +288,7 @@
             // TODO: remove when moved to the below package
             "frameworks/base/packages/ConnectivityT/framework-t/aidl-export",
             "packages/modules/Connectivity/framework/aidl-export",
+            "packages/modules/Media/apex/aidl/stable",
             "hardware/interfaces/graphics/common/aidl",
         ],
     },
@@ -538,6 +538,7 @@
             "frameworks/native/libs/permission/aidl",
             // TODO: remove when moved to the below package
             "frameworks/base/packages/ConnectivityT/framework-t/aidl-export",
+            "packages/modules/Media/apex/aidl/stable",
             "packages/modules/Connectivity/framework/aidl-export",
             "hardware/interfaces/graphics/common/aidl",
         ],
@@ -575,11 +576,9 @@
 stubs_defaults {
     name: "module-classpath-stubs-defaults",
     aidl: {
-        local_include_dirs: [
-            "apex/media/aidl/stable",
-        ],
         include_dirs: [
             "packages/modules/Connectivity/framework/aidl-export",
+            "packages/modules/Media/apex/aidl/stable",
         ],
     },
     libs: [
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 996cdc9..ba31161 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -145,11 +145,9 @@
         "api-versions-jars-dir",
     ],
     aidl: {
-        local_include_dirs: [
-            "apex/media/aidl/stable",
-        ],
         include_dirs: [
             "packages/modules/Connectivity/framework/aidl-export",
+            "packages/modules/Media/apex/aidl/stable",
         ],
     },
 }
diff --git a/apex/media/Android.bp b/apex/media/Android.bp
deleted file mode 100644
index 96e88dd..0000000
--- a/apex/media/Android.bp
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (C) 2020 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 {
-    default_visibility: [
-        ":__subpackages__",
-        "//frameworks/av/apex",
-        "//frameworks/av/apex/testing",
-    ],
-    // See: http://go/android-license-faq
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-sdk {
-    name: "media-module-sdk",
-    bootclasspath_fragments: ["com.android.media-bootclasspath-fragment"],
-    systemserverclasspath_fragments: ["com.android.media-systemserverclasspath-fragment"],
-    java_sdk_libs: [
-        "framework-media",
-    ],
-}
diff --git a/apex/media/OWNERS b/apex/media/OWNERS
deleted file mode 100644
index 2c5965c..0000000
--- a/apex/media/OWNERS
+++ /dev/null
@@ -1,12 +0,0 @@
-# Bug component: 1344
-hdmoon@google.com
-jinpark@google.com
-klhyun@google.com
-lnilsson@google.com
-sungsoo@google.com
-
-# go/android-fwk-media-solutions for info on areas of ownership.
-include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
-
-# media reliability team packages/delivers the media mainline builds.
-include platform/frameworks/av:/media/janitors/reliability_mainline_OWNERS
diff --git a/apex/media/aidl/Android.bp b/apex/media/aidl/Android.bp
deleted file mode 100644
index 4ba0d9b..0000000
--- a/apex/media/aidl/Android.bp
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// Copyright 2020 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 {
-    // See: http://go/android-license-faq
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-filegroup {
-    name: "stable-media-aidl-srcs",
-    srcs: ["stable/**/*.aidl"],
-    path: "stable",
-}
-
-filegroup {
-    name: "private-media-aidl-srcs",
-    srcs: ["private/**/I*.aidl"],
-    path: "private",
-}
-
-filegroup {
-    name: "media-aidl-srcs",
-    srcs: [
-        ":private-media-aidl-srcs",
-        ":stable-media-aidl-srcs",
-    ],
-}
diff --git a/apex/media/aidl/private/android/media/Controller2Link.aidl b/apex/media/aidl/private/android/media/Controller2Link.aidl
deleted file mode 100644
index 64edafc..0000000
--- a/apex/media/aidl/private/android/media/Controller2Link.aidl
+++ /dev/null
@@ -1,19 +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 android.media;
-
-parcelable Controller2Link;
diff --git a/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl b/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl
deleted file mode 100644
index e1c89e9..0000000
--- a/apex/media/aidl/private/android/media/IMediaCommunicationService.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Copyright 2020 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 android.media;
-
-import android.media.Session2Token;
-import android.media.IMediaCommunicationServiceCallback;
-import android.media.MediaParceledListSlice;
-import android.view.KeyEvent;
-
-/** {@hide} */
-interface IMediaCommunicationService {
-    void notifySession2Created(in Session2Token sessionToken);
-    boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid);
-    MediaParceledListSlice getSession2Tokens(int userId);
-
-   void dispatchMediaKeyEvent(String packageName, in KeyEvent keyEvent, boolean asSystemService);
-
-    void registerCallback(IMediaCommunicationServiceCallback callback, String packageName);
-    void unregisterCallback(IMediaCommunicationServiceCallback callback);
-}
-
diff --git a/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl b/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl
deleted file mode 100644
index e347ebf..0000000
--- a/apex/media/aidl/private/android/media/IMediaCommunicationServiceCallback.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Copyright 2021 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 android.media;
-
-import android.media.Session2Token;
-import android.media.MediaParceledListSlice;
-
-/** {@hide} */
-oneway interface IMediaCommunicationServiceCallback {
-    void onSession2Created(in Session2Token token);
-    void onSession2Changed(in MediaParceledListSlice tokens);
-}
-
diff --git a/apex/media/aidl/private/android/media/IMediaController2.aidl b/apex/media/aidl/private/android/media/IMediaController2.aidl
deleted file mode 100644
index 42c6e70..0000000
--- a/apex/media/aidl/private/android/media/IMediaController2.aidl
+++ /dev/null
@@ -1,39 +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 android.media;
-
-import android.os.Bundle;
-import android.os.ResultReceiver;
-import android.media.Session2Command;
-
-/**
- * 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.
- * @hide
- */
- // Code for AML only
-oneway interface IMediaController2 {
-    void notifyConnected(int seq, in Bundle connectionResult) = 0;
-    void notifyDisconnected(int seq) = 1;
-    void notifyPlaybackActiveChanged(int seq, boolean playbackActive) = 2;
-    void sendSessionCommand(int seq, in Session2Command command, in Bundle args,
-            in ResultReceiver resultReceiver) = 3;
-    void cancelSessionCommand(int seq) = 4;
-    // Next Id : 5
-}
diff --git a/apex/media/aidl/private/android/media/IMediaSession2.aidl b/apex/media/aidl/private/android/media/IMediaSession2.aidl
deleted file mode 100644
index 26e717b..0000000
--- a/apex/media/aidl/private/android/media/IMediaSession2.aidl
+++ /dev/null
@@ -1,39 +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 android.media;
-
-import android.os.Bundle;
-import android.os.ResultReceiver;
-import android.media.Controller2Link;
-import android.media.Session2Command;
-
-/**
- * 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.
- * @hide
- */
- // Code for AML only
-oneway interface IMediaSession2 {
-    void connect(in Controller2Link caller, int seq, in Bundle connectionRequest) = 0;
-    void disconnect(in Controller2Link caller, int seq) = 1;
-    void sendSessionCommand(in Controller2Link caller, int seq, in Session2Command sessionCommand,
-            in Bundle args, in ResultReceiver resultReceiver) = 2;
-    void cancelSessionCommand(in Controller2Link caller, int seq) = 3;
-    // Next Id : 4
-}
diff --git a/apex/media/aidl/private/android/media/IMediaSession2Service.aidl b/apex/media/aidl/private/android/media/IMediaSession2Service.aidl
deleted file mode 100644
index 10ac1be..0000000
--- a/apex/media/aidl/private/android/media/IMediaSession2Service.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2019 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 android.media;
-
-import android.os.Bundle;
-import android.media.Controller2Link;
-
-/**
- * Interface from MediaController2 to MediaSession2Service.
- * <p>
- * Keep this interface oneway. Otherwise a malicious app may implement fake version of this,
- * and holds calls from controller to make controller owner(s) frozen.
- * @hide
- */
-oneway interface IMediaSession2Service {
-    void connect(in Controller2Link caller, int seq, in Bundle connectionRequest) = 0;
-    // Next Id : 1
-}
diff --git a/apex/media/aidl/private/android/media/Session2Command.aidl b/apex/media/aidl/private/android/media/Session2Command.aidl
deleted file mode 100644
index 43a7b12..0000000
--- a/apex/media/aidl/private/android/media/Session2Command.aidl
+++ /dev/null
@@ -1,19 +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 android.media;
-
-parcelable Session2Command;
diff --git a/apex/media/aidl/stable/android/media/MediaParceledListSlice.aidl b/apex/media/aidl/stable/android/media/MediaParceledListSlice.aidl
deleted file mode 100644
index 92d673f..0000000
--- a/apex/media/aidl/stable/android/media/MediaParceledListSlice.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2020, 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 android.media;
-
-parcelable MediaParceledListSlice<T>;
diff --git a/apex/media/aidl/stable/android/media/Session2Token.aidl b/apex/media/aidl/stable/android/media/Session2Token.aidl
deleted file mode 100644
index c5980e9..0000000
--- a/apex/media/aidl/stable/android/media/Session2Token.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2019 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 android.media;
-
-parcelable Session2Token;
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
deleted file mode 100644
index e38488d..0000000
--- a/apex/media/framework/Android.bp
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright (C) 2020 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 {
-    // See: http://go/android-license-faq
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-java_library {
-    name: "updatable-media",
-
-    srcs: [
-        ":updatable-media-srcs",
-    ],
-
-    permitted_packages: [
-        "android.media",
-    ],
-
-    optimize: {
-        enabled: true,
-        shrink: true,
-        proguard_flags_files: ["updatable-media-proguard.flags"],
-    },
-
-    installable: true,
-
-    sdk_version: "module_current",
-    libs: [
-        "androidx.annotation_annotation",
-        "framework-annotations-lib",
-    ],
-    static_libs: [
-        "exoplayer2-extractor",
-        "mediatranscoding_aidl_interface-java",
-        "modules-annotation-minsdk",
-        "modules-utils-build",
-    ],
-    jarjar_rules: "jarjar_rules.txt",
-
-    plugins: ["java_api_finder"],
-
-    hostdex: true, // for hiddenapi check
-    apex_available: [
-        "com.android.media",
-        "test_com.android.media",
-    ],
-    min_sdk_version: "29",
-    lint: {
-        strict_updatability_linting: true,
-    },
-    visibility: [
-        "//frameworks/av/apex:__subpackages__",
-        "//frameworks/base/apex/media/service",
-        "//frameworks/base/api", // For framework-all
-        "//packages/modules/Media/apex/service",
-    ],
-}
-
-filegroup {
-    name: "updatable-media-srcs",
-    srcs: [
-        "java/android/media/MediaFrameworkInitializer.java",
-        ":media-aidl-srcs",
-        ":mediaparceledlistslice-java-srcs",
-        ":mediaparser-srcs",
-        ":mediasession2-java-srcs",
-        ":mediatranscoding-srcs",
-    ],
-    visibility: ["//frameworks/base"],
-}
-
-filegroup {
-    name: "mediasession2-java-srcs",
-    srcs: [
-        "java/android/media/Controller2Link.java",
-        "java/android/media/MediaConstants.java",
-        "java/android/media/MediaController2.java",
-        "java/android/media/MediaSession2.java",
-        "java/android/media/MediaSession2Service.java",
-        "java/android/media/Session2Command.java",
-        "java/android/media/Session2CommandGroup.java",
-        "java/android/media/Session2Link.java",
-        "java/android/media/Session2Token.java",
-        "java/android/media/MediaCommunicationManager.java",
-    ],
-    path: "java",
-}
-
-filegroup {
-    name: "mediaparceledlistslice-java-srcs",
-    srcs: [
-        "java/android/media/MediaParceledListSlice.java",
-        "java/android/media/BaseMediaParceledListSlice.java",
-    ],
-    path: "java",
-}
-
-filegroup {
-    name: "mediaparser-srcs",
-    srcs: [
-        "java/android/media/MediaParser.java",
-    ],
-    path: "java",
-}
-
-filegroup {
-    name: "mediatranscoding-srcs",
-    srcs: [
-        "java/android/media/ApplicationMediaCapabilities.java",
-        "java/android/media/MediaFeature.java",
-        "java/android/media/MediaTranscodingManager.java",
-    ],
-    path: "java",
-}
-
-java_sdk_library {
-    name: "framework-media",
-    defaults: ["framework-module-defaults"],
-
-    // This is only used to define the APIs for updatable-media.
-    api_only: true,
-
-    srcs: [
-        ":updatable-media-srcs",
-    ],
-
-    impl_library_visibility: ["//frameworks/av/apex:__subpackages__"],
-}
-
-cc_library_shared {
-    name: "libmediaparser-jni",
-    srcs: [
-        "jni/android_media_MediaParserJNI.cpp",
-    ],
-    header_libs: ["jni_headers"],
-    shared_libs: [
-        "libandroid",
-        "liblog",
-        "libmediametrics",
-    ],
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-unused-parameter",
-        "-Wunreachable-code",
-        "-Wunused",
-    ],
-    apex_available: [
-        "com.android.media",
-    ],
-    min_sdk_version: "29",
-}
diff --git a/apex/media/framework/TEST_MAPPING b/apex/media/framework/TEST_MAPPING
deleted file mode 100644
index 3d21914..0000000
--- a/apex/media/framework/TEST_MAPPING
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "CtsMediaParserTestCases"
-    },
-    {
-      "name": "CtsMediaParserHostTestCases"
-    }
-  ]
-}
diff --git a/apex/media/framework/api/current.txt b/apex/media/framework/api/current.txt
deleted file mode 100644
index b7d7ed8..0000000
--- a/apex/media/framework/api/current.txt
+++ /dev/null
@@ -1,267 +0,0 @@
-// Signature format: 2.0
-package android.media {
-
-  public final class ApplicationMediaCapabilities implements android.os.Parcelable {
-    method @NonNull public static android.media.ApplicationMediaCapabilities createFromXml(@NonNull org.xmlpull.v1.XmlPullParser);
-    method public int describeContents();
-    method @NonNull public java.util.List<java.lang.String> getSupportedHdrTypes();
-    method @NonNull public java.util.List<java.lang.String> getSupportedVideoMimeTypes();
-    method @NonNull public java.util.List<java.lang.String> getUnsupportedHdrTypes();
-    method @NonNull public java.util.List<java.lang.String> getUnsupportedVideoMimeTypes();
-    method public boolean isFormatSpecified(@NonNull String);
-    method public boolean isHdrTypeSupported(@NonNull String);
-    method public boolean isVideoMimeTypeSupported(@NonNull String);
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.media.ApplicationMediaCapabilities> CREATOR;
-  }
-
-  public static final class ApplicationMediaCapabilities.Builder {
-    ctor public ApplicationMediaCapabilities.Builder();
-    method @NonNull public android.media.ApplicationMediaCapabilities.Builder addSupportedHdrType(@NonNull String);
-    method @NonNull public android.media.ApplicationMediaCapabilities.Builder addSupportedVideoMimeType(@NonNull String);
-    method @NonNull public android.media.ApplicationMediaCapabilities.Builder addUnsupportedHdrType(@NonNull String);
-    method @NonNull public android.media.ApplicationMediaCapabilities.Builder addUnsupportedVideoMimeType(@NonNull String);
-    method @NonNull public android.media.ApplicationMediaCapabilities build();
-  }
-
-  public class MediaCommunicationManager {
-    method @NonNull public java.util.List<android.media.Session2Token> getSession2Tokens();
-    method @IntRange(from=1) public int getVersion();
-  }
-
-  public class MediaController2 implements java.lang.AutoCloseable {
-    method public void cancelSessionCommand(@NonNull Object);
-    method public void close();
-    method @Nullable public android.media.Session2Token getConnectedToken();
-    method public boolean isPlaybackActive();
-    method @NonNull public Object sendSessionCommand(@NonNull android.media.Session2Command, @Nullable android.os.Bundle);
-  }
-
-  public static final class MediaController2.Builder {
-    ctor public MediaController2.Builder(@NonNull android.content.Context, @NonNull android.media.Session2Token);
-    method @NonNull public android.media.MediaController2 build();
-    method @NonNull public android.media.MediaController2.Builder setConnectionHints(@NonNull android.os.Bundle);
-    method @NonNull public android.media.MediaController2.Builder setControllerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaController2.ControllerCallback);
-  }
-
-  public abstract static class MediaController2.ControllerCallback {
-    ctor public MediaController2.ControllerCallback();
-    method public void onCommandResult(@NonNull android.media.MediaController2, @NonNull Object, @NonNull android.media.Session2Command, @NonNull android.media.Session2Command.Result);
-    method public void onConnected(@NonNull android.media.MediaController2, @NonNull android.media.Session2CommandGroup);
-    method public void onDisconnected(@NonNull android.media.MediaController2);
-    method public void onPlaybackActiveChanged(@NonNull android.media.MediaController2, boolean);
-    method @Nullable public android.media.Session2Command.Result onSessionCommand(@NonNull android.media.MediaController2, @NonNull android.media.Session2Command, @Nullable android.os.Bundle);
-  }
-
-  public final class MediaFeature {
-    ctor public MediaFeature();
-  }
-
-  public static final class MediaFeature.HdrType {
-    field public static final String DOLBY_VISION = "android.media.feature.hdr.dolby_vision";
-    field public static final String HDR10 = "android.media.feature.hdr.hdr10";
-    field public static final String HDR10_PLUS = "android.media.feature.hdr.hdr10_plus";
-    field public static final String HLG = "android.media.feature.hdr.hlg";
-  }
-
-  public final class MediaParser {
-    method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException;
-    method @NonNull public static android.media.MediaParser create(@NonNull android.media.MediaParser.OutputConsumer, @NonNull java.lang.String...);
-    method @NonNull public static android.media.MediaParser createByName(@NonNull String, @NonNull android.media.MediaParser.OutputConsumer);
-    method @NonNull public android.media.metrics.LogSessionId getLogSessionId();
-    method @NonNull public String getParserName();
-    method @NonNull public static java.util.List<java.lang.String> getParserNames(@NonNull android.media.MediaFormat);
-    method public void release();
-    method public void seek(@NonNull android.media.MediaParser.SeekPoint);
-    method public void setLogSessionId(@NonNull android.media.metrics.LogSessionId);
-    method @NonNull public android.media.MediaParser setParameter(@NonNull String, @NonNull Object);
-    method public boolean supportsParameter(@NonNull String);
-    field public static final String PARAMETER_ADTS_ENABLE_CBR_SEEKING = "android.media.mediaparser.adts.enableCbrSeeking";
-    field public static final String PARAMETER_AMR_ENABLE_CBR_SEEKING = "android.media.mediaparser.amr.enableCbrSeeking";
-    field public static final String PARAMETER_FLAC_DISABLE_ID3 = "android.media.mediaparser.flac.disableId3";
-    field public static final String PARAMETER_MATROSKA_DISABLE_CUES_SEEKING = "android.media.mediaparser.matroska.disableCuesSeeking";
-    field public static final String PARAMETER_MP3_DISABLE_ID3 = "android.media.mediaparser.mp3.disableId3";
-    field public static final String PARAMETER_MP3_ENABLE_CBR_SEEKING = "android.media.mediaparser.mp3.enableCbrSeeking";
-    field public static final String PARAMETER_MP3_ENABLE_INDEX_SEEKING = "android.media.mediaparser.mp3.enableIndexSeeking";
-    field public static final String PARAMETER_MP4_IGNORE_EDIT_LISTS = "android.media.mediaparser.mp4.ignoreEditLists";
-    field public static final String PARAMETER_MP4_IGNORE_TFDT_BOX = "android.media.mediaparser.mp4.ignoreTfdtBox";
-    field public static final String PARAMETER_MP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES = "android.media.mediaparser.mp4.treatVideoFramesAsKeyframes";
-    field public static final String PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES = "android.media.mediaparser.ts.allowNonIdrAvcKeyframes";
-    field public static final String PARAMETER_TS_DETECT_ACCESS_UNITS = "android.media.mediaparser.ts.ignoreDetectAccessUnits";
-    field public static final String PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS = "android.media.mediaparser.ts.enableHdmvDtsAudioStreams";
-    field public static final String PARAMETER_TS_IGNORE_AAC_STREAM = "android.media.mediaparser.ts.ignoreAacStream";
-    field public static final String PARAMETER_TS_IGNORE_AVC_STREAM = "android.media.mediaparser.ts.ignoreAvcStream";
-    field public static final String PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM = "android.media.mediaparser.ts.ignoreSpliceInfoStream";
-    field public static final String PARAMETER_TS_MODE = "android.media.mediaparser.ts.mode";
-    field public static final String PARSER_NAME_AC3 = "android.media.mediaparser.Ac3Parser";
-    field public static final String PARSER_NAME_AC4 = "android.media.mediaparser.Ac4Parser";
-    field public static final String PARSER_NAME_ADTS = "android.media.mediaparser.AdtsParser";
-    field public static final String PARSER_NAME_AMR = "android.media.mediaparser.AmrParser";
-    field public static final String PARSER_NAME_FLAC = "android.media.mediaparser.FlacParser";
-    field public static final String PARSER_NAME_FLV = "android.media.mediaparser.FlvParser";
-    field public static final String PARSER_NAME_FMP4 = "android.media.mediaparser.FragmentedMp4Parser";
-    field public static final String PARSER_NAME_MATROSKA = "android.media.mediaparser.MatroskaParser";
-    field public static final String PARSER_NAME_MP3 = "android.media.mediaparser.Mp3Parser";
-    field public static final String PARSER_NAME_MP4 = "android.media.mediaparser.Mp4Parser";
-    field public static final String PARSER_NAME_OGG = "android.media.mediaparser.OggParser";
-    field public static final String PARSER_NAME_PS = "android.media.mediaparser.PsParser";
-    field public static final String PARSER_NAME_TS = "android.media.mediaparser.TsParser";
-    field public static final String PARSER_NAME_UNKNOWN = "android.media.mediaparser.UNKNOWN";
-    field public static final String PARSER_NAME_WAV = "android.media.mediaparser.WavParser";
-    field public static final int SAMPLE_FLAG_DECODE_ONLY = -2147483648; // 0x80000000
-    field public static final int SAMPLE_FLAG_ENCRYPTED = 1073741824; // 0x40000000
-    field public static final int SAMPLE_FLAG_HAS_SUPPLEMENTAL_DATA = 268435456; // 0x10000000
-    field public static final int SAMPLE_FLAG_KEY_FRAME = 1; // 0x1
-    field public static final int SAMPLE_FLAG_LAST_SAMPLE = 536870912; // 0x20000000
-  }
-
-  public static interface MediaParser.InputReader {
-    method public long getLength();
-    method public long getPosition();
-    method public int read(@NonNull byte[], int, int) throws java.io.IOException;
-  }
-
-  public static interface MediaParser.OutputConsumer {
-    method public void onSampleCompleted(int, long, int, int, int, @Nullable android.media.MediaCodec.CryptoInfo);
-    method public void onSampleDataFound(int, @NonNull android.media.MediaParser.InputReader) throws java.io.IOException;
-    method public void onSeekMapFound(@NonNull android.media.MediaParser.SeekMap);
-    method public void onTrackCountFound(int);
-    method public void onTrackDataFound(int, @NonNull android.media.MediaParser.TrackData);
-  }
-
-  public static final class MediaParser.ParsingException extends java.io.IOException {
-  }
-
-  public static final class MediaParser.SeekMap {
-    method public long getDurationMicros();
-    method @NonNull public android.util.Pair<android.media.MediaParser.SeekPoint,android.media.MediaParser.SeekPoint> getSeekPoints(long);
-    method public boolean isSeekable();
-    field public static final int UNKNOWN_DURATION = -2147483648; // 0x80000000
-  }
-
-  public static final class MediaParser.SeekPoint {
-    field @NonNull public static final android.media.MediaParser.SeekPoint START;
-    field public final long position;
-    field public final long timeMicros;
-  }
-
-  public static interface MediaParser.SeekableInputReader extends android.media.MediaParser.InputReader {
-    method public void seekToPosition(long);
-  }
-
-  public static final class MediaParser.TrackData {
-    field @Nullable public final android.media.DrmInitData drmInitData;
-    field @NonNull public final android.media.MediaFormat mediaFormat;
-  }
-
-  public static final class MediaParser.UnrecognizedInputFormatException extends java.io.IOException {
-  }
-
-  public class MediaSession2 implements java.lang.AutoCloseable {
-    method public void broadcastSessionCommand(@NonNull android.media.Session2Command, @Nullable android.os.Bundle);
-    method public void cancelSessionCommand(@NonNull android.media.MediaSession2.ControllerInfo, @NonNull Object);
-    method public void close();
-    method @NonNull public java.util.List<android.media.MediaSession2.ControllerInfo> getConnectedControllers();
-    method @NonNull public String getId();
-    method @NonNull public android.media.Session2Token getToken();
-    method public boolean isPlaybackActive();
-    method @NonNull public Object sendSessionCommand(@NonNull android.media.MediaSession2.ControllerInfo, @NonNull android.media.Session2Command, @Nullable android.os.Bundle);
-    method public void setPlaybackActive(boolean);
-  }
-
-  public static final class MediaSession2.Builder {
-    ctor public MediaSession2.Builder(@NonNull android.content.Context);
-    method @NonNull public android.media.MediaSession2 build();
-    method @NonNull public android.media.MediaSession2.Builder setExtras(@NonNull android.os.Bundle);
-    method @NonNull public android.media.MediaSession2.Builder setId(@NonNull String);
-    method @NonNull public android.media.MediaSession2.Builder setSessionActivity(@Nullable android.app.PendingIntent);
-    method @NonNull public android.media.MediaSession2.Builder setSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaSession2.SessionCallback);
-  }
-
-  public static final class MediaSession2.ControllerInfo {
-    method @NonNull public android.os.Bundle getConnectionHints();
-    method @NonNull public String getPackageName();
-    method @NonNull public android.media.session.MediaSessionManager.RemoteUserInfo getRemoteUserInfo();
-    method public int getUid();
-  }
-
-  public abstract static class MediaSession2.SessionCallback {
-    ctor public MediaSession2.SessionCallback();
-    method public void onCommandResult(@NonNull android.media.MediaSession2, @NonNull android.media.MediaSession2.ControllerInfo, @NonNull Object, @NonNull android.media.Session2Command, @NonNull android.media.Session2Command.Result);
-    method @Nullable public android.media.Session2CommandGroup onConnect(@NonNull android.media.MediaSession2, @NonNull android.media.MediaSession2.ControllerInfo);
-    method public void onDisconnected(@NonNull android.media.MediaSession2, @NonNull android.media.MediaSession2.ControllerInfo);
-    method public void onPostConnect(@NonNull android.media.MediaSession2, @NonNull android.media.MediaSession2.ControllerInfo);
-    method @Nullable public android.media.Session2Command.Result onSessionCommand(@NonNull android.media.MediaSession2, @NonNull android.media.MediaSession2.ControllerInfo, @NonNull android.media.Session2Command, @Nullable android.os.Bundle);
-  }
-
-  public abstract class MediaSession2Service extends android.app.Service {
-    ctor public MediaSession2Service();
-    method public final void addSession(@NonNull android.media.MediaSession2);
-    method @NonNull public final java.util.List<android.media.MediaSession2> getSessions();
-    method @CallSuper @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
-    method @Nullable public abstract android.media.MediaSession2 onGetSession(@NonNull android.media.MediaSession2.ControllerInfo);
-    method @Nullable public abstract android.media.MediaSession2Service.MediaNotification onUpdateNotification(@NonNull android.media.MediaSession2);
-    method public final void removeSession(@NonNull android.media.MediaSession2);
-    field public static final String SERVICE_INTERFACE = "android.media.MediaSession2Service";
-  }
-
-  public static class MediaSession2Service.MediaNotification {
-    ctor public MediaSession2Service.MediaNotification(int, @NonNull android.app.Notification);
-    method @NonNull public android.app.Notification getNotification();
-    method public int getNotificationId();
-  }
-
-  public final class Session2Command implements android.os.Parcelable {
-    ctor public Session2Command(int);
-    ctor public Session2Command(@NonNull String, @Nullable android.os.Bundle);
-    method public int describeContents();
-    method public int getCommandCode();
-    method @Nullable public String getCustomAction();
-    method @Nullable public android.os.Bundle getCustomExtras();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int COMMAND_CODE_CUSTOM = 0; // 0x0
-    field @NonNull public static final android.os.Parcelable.Creator<android.media.Session2Command> CREATOR;
-  }
-
-  public static final class Session2Command.Result {
-    ctor public Session2Command.Result(int, @Nullable android.os.Bundle);
-    method public int getResultCode();
-    method @Nullable public android.os.Bundle getResultData();
-    field public static final int RESULT_ERROR_UNKNOWN_ERROR = -1; // 0xffffffff
-    field public static final int RESULT_INFO_SKIPPED = 1; // 0x1
-    field public static final int RESULT_SUCCESS = 0; // 0x0
-  }
-
-  public final class Session2CommandGroup implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public java.util.Set<android.media.Session2Command> getCommands();
-    method public boolean hasCommand(@NonNull android.media.Session2Command);
-    method public boolean hasCommand(int);
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.media.Session2CommandGroup> CREATOR;
-  }
-
-  public static final class Session2CommandGroup.Builder {
-    ctor public Session2CommandGroup.Builder();
-    ctor public Session2CommandGroup.Builder(@NonNull android.media.Session2CommandGroup);
-    method @NonNull public android.media.Session2CommandGroup.Builder addCommand(@NonNull android.media.Session2Command);
-    method @NonNull public android.media.Session2CommandGroup build();
-    method @NonNull public android.media.Session2CommandGroup.Builder removeCommand(@NonNull android.media.Session2Command);
-  }
-
-  public final class Session2Token implements android.os.Parcelable {
-    ctor public Session2Token(@NonNull android.content.Context, @NonNull android.content.ComponentName);
-    method public int describeContents();
-    method @NonNull public android.os.Bundle getExtras();
-    method @NonNull public String getPackageName();
-    method @Nullable public String getServiceName();
-    method public int getType();
-    method public int getUid();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.media.Session2Token> CREATOR;
-    field public static final int TYPE_SESSION = 0; // 0x0
-    field public static final int TYPE_SESSION_SERVICE = 1; // 0x1
-  }
-
-}
-
diff --git a/apex/media/framework/api/module-lib-current.txt b/apex/media/framework/api/module-lib-current.txt
deleted file mode 100644
index 7317f14..0000000
--- a/apex/media/framework/api/module-lib-current.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-// Signature format: 2.0
-package android.media {
-
-  public class MediaCommunicationManager {
-    method public void dispatchMediaKeyEvent(@NonNull android.view.KeyEvent, boolean);
-    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaCommunicationManager.SessionCallback);
-    method public void unregisterSessionCallback(@NonNull android.media.MediaCommunicationManager.SessionCallback);
-  }
-
-  public static interface MediaCommunicationManager.SessionCallback {
-    method public default void onSession2TokenCreated(@NonNull android.media.Session2Token);
-    method public default void onSession2TokensChanged(@NonNull java.util.List<android.media.Session2Token>);
-  }
-
-  public class MediaFrameworkInitializer {
-    method public static void registerServiceWrappers();
-    method public static void setMediaServiceManager(@NonNull android.media.MediaServiceManager);
-  }
-
-  @Deprecated public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable {
-    ctor @Deprecated public MediaParceledListSlice(@NonNull java.util.List<T>);
-    method @Deprecated public int describeContents();
-    method @Deprecated @NonNull public static <T extends android.os.Parcelable> android.media.MediaParceledListSlice<T> emptyList();
-    method @Deprecated public java.util.List<T> getList();
-    method @Deprecated public void setInlineCountLimit(int);
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated @NonNull public static final android.os.Parcelable.ClassLoaderCreator<android.media.MediaParceledListSlice> CREATOR;
-  }
-
-}
-
diff --git a/apex/media/framework/api/module-lib-removed.txt b/apex/media/framework/api/module-lib-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/media/framework/api/module-lib-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/media/framework/api/removed.txt b/apex/media/framework/api/removed.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/media/framework/api/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/media/framework/api/system-current.txt b/apex/media/framework/api/system-current.txt
deleted file mode 100644
index 6eea769..0000000
--- a/apex/media/framework/api/system-current.txt
+++ /dev/null
@@ -1,68 +0,0 @@
-// Signature format: 2.0
-package android.media {
-
-  public final class MediaTranscodingManager {
-    method @Nullable public android.media.MediaTranscodingManager.TranscodingSession enqueueRequest(@NonNull android.media.MediaTranscodingManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodingManager.OnTranscodingFinishedListener);
-  }
-
-  @java.lang.FunctionalInterface public static interface MediaTranscodingManager.OnTranscodingFinishedListener {
-    method public void onTranscodingFinished(@NonNull android.media.MediaTranscodingManager.TranscodingSession);
-  }
-
-  public abstract static class MediaTranscodingManager.TranscodingRequest {
-    method public int getClientPid();
-    method public int getClientUid();
-    method @Nullable public android.os.ParcelFileDescriptor getDestinationFileDescriptor();
-    method @NonNull public android.net.Uri getDestinationUri();
-    method @Nullable public android.os.ParcelFileDescriptor getSourceFileDescriptor();
-    method @NonNull public android.net.Uri getSourceUri();
-  }
-
-  public static class MediaTranscodingManager.TranscodingRequest.VideoFormatResolver {
-    ctor public MediaTranscodingManager.TranscodingRequest.VideoFormatResolver(@NonNull android.media.ApplicationMediaCapabilities, @NonNull android.media.MediaFormat);
-    method @Nullable public android.media.MediaFormat resolveVideoFormat();
-    method public boolean shouldTranscode();
-  }
-
-  public static final class MediaTranscodingManager.TranscodingSession {
-    method public boolean addClientUid(int);
-    method public void cancel();
-    method @NonNull public java.util.List<java.lang.Integer> getClientUids();
-    method public int getErrorCode();
-    method @IntRange(from=0, to=100) public int getProgress();
-    method public int getResult();
-    method public int getSessionId();
-    method public int getStatus();
-    method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodingManager.TranscodingSession.OnProgressUpdateListener);
-    field public static final int ERROR_DROPPED_BY_SERVICE = 1; // 0x1
-    field public static final int ERROR_NONE = 0; // 0x0
-    field public static final int ERROR_SERVICE_DIED = 2; // 0x2
-    field public static final int RESULT_CANCELED = 4; // 0x4
-    field public static final int RESULT_ERROR = 3; // 0x3
-    field public static final int RESULT_NONE = 1; // 0x1
-    field public static final int RESULT_SUCCESS = 2; // 0x2
-    field public static final int STATUS_FINISHED = 3; // 0x3
-    field public static final int STATUS_PAUSED = 4; // 0x4
-    field public static final int STATUS_PENDING = 1; // 0x1
-    field public static final int STATUS_RUNNING = 2; // 0x2
-  }
-
-  @java.lang.FunctionalInterface public static interface MediaTranscodingManager.TranscodingSession.OnProgressUpdateListener {
-    method public void onProgressUpdate(@NonNull android.media.MediaTranscodingManager.TranscodingSession, @IntRange(from=0, to=100) int);
-  }
-
-  public static final class MediaTranscodingManager.VideoTranscodingRequest extends android.media.MediaTranscodingManager.TranscodingRequest {
-    method @NonNull public android.media.MediaFormat getVideoTrackFormat();
-  }
-
-  public static final class MediaTranscodingManager.VideoTranscodingRequest.Builder {
-    ctor public MediaTranscodingManager.VideoTranscodingRequest.Builder(@NonNull android.net.Uri, @NonNull android.net.Uri, @NonNull android.media.MediaFormat);
-    method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest build();
-    method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setClientPid(int);
-    method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setClientUid(int);
-    method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setDestinationFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
-    method @NonNull public android.media.MediaTranscodingManager.VideoTranscodingRequest.Builder setSourceFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
-  }
-
-}
-
diff --git a/apex/media/framework/api/system-removed.txt b/apex/media/framework/api/system-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/media/framework/api/system-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/media/framework/jarjar_rules.txt b/apex/media/framework/jarjar_rules.txt
deleted file mode 100644
index 91489dc..0000000
--- a/apex/media/framework/jarjar_rules.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-rule com.android.modules.** android.media.internal.@1
-rule com.google.android.exoplayer2.** android.media.internal.exo.@1
diff --git a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
deleted file mode 100644
index 97fa0ec..0000000
--- a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
+++ /dev/null
@@ -1,626 +0,0 @@
-/*
- * Copyright (C) 2020 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 android.media;
-
-import android.annotation.NonNull;
-import android.content.ContentResolver;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
-
-import com.android.modules.annotation.MinSdk;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- ApplicationMediaCapabilities is an immutable class that encapsulates an application's capabilities
- for handling newer video codec format and media features.
-
- <p>
- Android 12 introduces Compatible media transcoding feature.  See
- <a href="https://developer.android.com/about/versions/12/features#compatible_media_transcoding">
- Compatible media transcoding</a>. By default, Android assumes apps can support playback of all
- media formats. Apps that would like to request that media be transcoded into a more compatible
- format should declare their media capabilities in a media_capabilities.xml resource file and add it
- as a property tag in the AndroidManifest.xml file. Here is a example:
- <pre>
- {@code
- <media-capabilities xmlns:android="http://schemas.android.com/apk/res/android">
-     <format android:name="HEVC" supported="true"/>
-     <format android:name="HDR10" supported="false"/>
-     <format android:name="HDR10Plus" supported="false"/>
- </media-capabilities>
- }
- </pre>
- The ApplicationMediaCapabilities class is generated from this xml and used by the platform to
- represent an application's media capabilities in order to determine whether modern media files need
- to be transcoded for that application.
- </p>
-
- <p>
- ApplicationMediaCapabilities objects can also be built by applications at runtime for use with
- {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)} to provide more
- control over the transcoding that is built into the platform. ApplicationMediaCapabilities
- provided by applications at runtime like this override the default manifest capabilities for that
- media access.The object could be build either through {@link #createFromXml(XmlPullParser)} or
- through the builder class {@link ApplicationMediaCapabilities.Builder}
-
- <h3> Video Codec Support</h3>
- <p>
- Newer video codes include HEVC, VP9 and AV1. Application only needs to indicate their support
- for newer format with this class as they are assumed to support older format like h.264.
-
- <h3>Capability of handling HDR(high dynamic range) video</h3>
- <p>
- There are four types of HDR video(Dolby-Vision, HDR10, HDR10+, HLG) supported by the platform,
- application will only need to specify individual types they supported.
- */
-@MinSdk(Build.VERSION_CODES.S)
-public final class ApplicationMediaCapabilities implements Parcelable {
-    private static final String TAG = "ApplicationMediaCapabilities";
-
-    /** List of supported video codec mime types. */
-    private Set<String> mSupportedVideoMimeTypes = new HashSet<>();
-
-    /** List of unsupported video codec mime types. */
-    private Set<String> mUnsupportedVideoMimeTypes = new HashSet<>();
-
-    /** List of supported hdr types. */
-    private Set<String> mSupportedHdrTypes = new HashSet<>();
-
-    /** List of unsupported hdr types. */
-    private Set<String> mUnsupportedHdrTypes = new HashSet<>();
-
-    private boolean mIsSlowMotionSupported = false;
-
-    private ApplicationMediaCapabilities(Builder b) {
-        mSupportedVideoMimeTypes.addAll(b.getSupportedVideoMimeTypes());
-        mUnsupportedVideoMimeTypes.addAll(b.getUnsupportedVideoMimeTypes());
-        mSupportedHdrTypes.addAll(b.getSupportedHdrTypes());
-        mUnsupportedHdrTypes.addAll(b.getUnsupportedHdrTypes());
-        mIsSlowMotionSupported = b.mIsSlowMotionSupported;
-    }
-
-    /**
-     * Query if a video codec format is supported by the application.
-     * <p>
-     * If the application has not specified supporting the format or not, this will return false.
-     * Use {@link #isFormatSpecified(String)} to query if a format is specified or not.
-     *
-     * @param videoMime The mime type of the video codec format. Must be the one used in
-     * {@link MediaFormat#KEY_MIME}.
-     * @return true if application supports the video codec format, false otherwise.
-     */
-    public boolean isVideoMimeTypeSupported(
-            @NonNull String videoMime) {
-        if (mSupportedVideoMimeTypes.contains(videoMime.toLowerCase())) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Query if a HDR type is supported by the application.
-     * <p>
-     * If the application has not specified supporting the format or not, this will return false.
-     * Use {@link #isFormatSpecified(String)} to query if a format is specified or not.
-     *
-     * @param hdrType The type of the HDR format.
-     * @return true if application supports the HDR format, false otherwise.
-     */
-    public boolean isHdrTypeSupported(
-            @NonNull @MediaFeature.MediaHdrType String hdrType) {
-        if (mSupportedHdrTypes.contains(hdrType)) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Query if a format is specified by the application.
-     * <p>
-     * The format could be either the video format or the hdr format.
-     *
-     * @param format The name of the format.
-     * @return true if application specifies the format, false otherwise.
-     */
-    public boolean isFormatSpecified(@NonNull String format) {
-        if (mSupportedVideoMimeTypes.contains(format) || mUnsupportedVideoMimeTypes.contains(format)
-                || mSupportedHdrTypes.contains(format) || mUnsupportedHdrTypes.contains(format)) {
-            return true;
-
-        }
-        return false;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        // Write out the supported video mime types.
-        dest.writeInt(mSupportedVideoMimeTypes.size());
-        for (String cap : mSupportedVideoMimeTypes) {
-            dest.writeString(cap);
-        }
-        // Write out the unsupported video mime types.
-        dest.writeInt(mUnsupportedVideoMimeTypes.size());
-        for (String cap : mUnsupportedVideoMimeTypes) {
-            dest.writeString(cap);
-        }
-        // Write out the supported hdr types.
-        dest.writeInt(mSupportedHdrTypes.size());
-        for (String cap : mSupportedHdrTypes) {
-            dest.writeString(cap);
-        }
-        // Write out the unsupported hdr types.
-        dest.writeInt(mUnsupportedHdrTypes.size());
-        for (String cap : mUnsupportedHdrTypes) {
-            dest.writeString(cap);
-        }
-        // Write out the supported slow motion.
-        dest.writeBoolean(mIsSlowMotionSupported);
-    }
-
-    @Override
-    public String toString() {
-        String caps = new String(
-                "Supported Video MimeTypes: " + mSupportedVideoMimeTypes.toString());
-        caps += "Unsupported Video MimeTypes: " + mUnsupportedVideoMimeTypes.toString();
-        caps += "Supported HDR types: " + mSupportedHdrTypes.toString();
-        caps += "Unsupported HDR types: " + mUnsupportedHdrTypes.toString();
-        caps += "Supported slow motion: " + mIsSlowMotionSupported;
-        return caps;
-    }
-
-    @NonNull
-    public static final Creator<ApplicationMediaCapabilities> CREATOR =
-            new Creator<ApplicationMediaCapabilities>() {
-                public ApplicationMediaCapabilities createFromParcel(Parcel in) {
-                    ApplicationMediaCapabilities.Builder builder =
-                            new ApplicationMediaCapabilities.Builder();
-
-                    // Parse supported video codec mime types.
-                    int count = in.readInt();
-                    for (int readCount = 0; readCount < count; ++readCount) {
-                        builder.addSupportedVideoMimeType(in.readString());
-                    }
-
-                    // Parse unsupported video codec mime types.
-                    count = in.readInt();
-                    for (int readCount = 0; readCount < count; ++readCount) {
-                        builder.addUnsupportedVideoMimeType(in.readString());
-                    }
-
-                    // Parse supported hdr types.
-                    count = in.readInt();
-                    for (int readCount = 0; readCount < count; ++readCount) {
-                        builder.addSupportedHdrType(in.readString());
-                    }
-
-                    // Parse unsupported hdr types.
-                    count = in.readInt();
-                    for (int readCount = 0; readCount < count; ++readCount) {
-                        builder.addUnsupportedHdrType(in.readString());
-                    }
-
-                    boolean supported = in.readBoolean();
-                    builder.setSlowMotionSupported(supported);
-
-                    return builder.build();
-                }
-
-                public ApplicationMediaCapabilities[] newArray(int size) {
-                    return new ApplicationMediaCapabilities[size];
-                }
-            };
-
-    /**
-     * Query the video codec mime types supported by the application.
-     * @return List of supported video codec mime types. The list will be empty if there are none.
-     */
-    @NonNull
-    public List<String> getSupportedVideoMimeTypes() {
-        return new ArrayList<>(mSupportedVideoMimeTypes);
-    }
-
-    /**
-     * Query the video codec mime types that are not supported by the application.
-     * @return List of unsupported video codec mime types. The list will be empty if there are none.
-     */
-    @NonNull
-    public List<String> getUnsupportedVideoMimeTypes() {
-        return new ArrayList<>(mUnsupportedVideoMimeTypes);
-    }
-
-    /**
-     * Query all hdr types that are supported by the application.
-     * @return List of supported hdr types. The list will be empty if there are none.
-     */
-    @NonNull
-    public List<String> getSupportedHdrTypes() {
-        return new ArrayList<>(mSupportedHdrTypes);
-    }
-
-    /**
-     * Query all hdr types that are not supported by the application.
-     * @return List of unsupported hdr types. The list will be empty if there are none.
-     */
-    @NonNull
-    public List<String> getUnsupportedHdrTypes()  {
-        return new ArrayList<>(mUnsupportedHdrTypes);
-    }
-
-    /**
-     * Whether handling of slow-motion video is supported
-     * @hide
-     */
-    public boolean isSlowMotionSupported() {
-        return mIsSlowMotionSupported;
-    }
-
-    /**
-     * Creates {@link ApplicationMediaCapabilities} from an xml.
-     *
-     * The xml's syntax is the same as the media_capabilities.xml used by the AndroidManifest.xml.
-     * <p> Here is an example:
-     *
-     * <pre>
-     * {@code
-     * <media-capabilities xmlns:android="http://schemas.android.com/apk/res/android">
-     *     <format android:name="HEVC" supported="true"/>
-     *     <format android:name="HDR10" supported="false"/>
-     *     <format android:name="HDR10Plus" supported="false"/>
-     * </media-capabilities>
-     * }
-     * </pre>
-     * <p>
-     *
-     * @param xmlParser The underlying {@link XmlPullParser} that will read the xml.
-     * @return An ApplicationMediaCapabilities object.
-     * @throws UnsupportedOperationException if the capabilities in xml config are invalid or
-     * incompatible.
-     */
-    // TODO: Add developer.android.com link for the format of the xml.
-    @NonNull
-    public static ApplicationMediaCapabilities createFromXml(@NonNull XmlPullParser xmlParser) {
-        ApplicationMediaCapabilities.Builder builder = new ApplicationMediaCapabilities.Builder();
-        builder.parseXml(xmlParser);
-        return builder.build();
-    }
-
-    /**
-     * Builder class for {@link ApplicationMediaCapabilities} objects.
-     * Use this class to configure and create an ApplicationMediaCapabilities instance. Builder
-     * could be created from an existing ApplicationMediaCapabilities object, from a xml file or
-     * MediaCodecList.
-     * //TODO(hkuang): Add xml parsing support to the builder.
-     */
-    public final static class Builder {
-        /** List of supported video codec mime types. */
-        private Set<String> mSupportedVideoMimeTypes = new HashSet<>();
-
-        /** List of supported hdr types. */
-        private Set<String> mSupportedHdrTypes = new HashSet<>();
-
-        /** List of unsupported video codec mime types. */
-        private Set<String> mUnsupportedVideoMimeTypes = new HashSet<>();
-
-        /** List of unsupported hdr types. */
-        private Set<String> mUnsupportedHdrTypes = new HashSet<>();
-
-        private boolean mIsSlowMotionSupported = false;
-
-        /* Map to save the format read from the xml. */
-        private Map<String, Boolean> mFormatSupportedMap =  new HashMap<String, Boolean>();
-
-        /**
-         * Constructs a new Builder with all the supports default to false.
-         */
-        public Builder() {
-        }
-
-        private void parseXml(@NonNull XmlPullParser xmlParser)
-                throws UnsupportedOperationException {
-            if (xmlParser == null) {
-                throw new IllegalArgumentException("XmlParser must not be null");
-            }
-
-            try {
-                while (xmlParser.next() != XmlPullParser.START_TAG) {
-                    continue;
-                }
-
-                // Validates the tag is "media-capabilities".
-                if (!xmlParser.getName().equals("media-capabilities")) {
-                    throw new UnsupportedOperationException("Invalid tag");
-                }
-
-                xmlParser.next();
-                while (xmlParser.getEventType() != XmlPullParser.END_TAG) {
-                    while (xmlParser.getEventType() != XmlPullParser.START_TAG) {
-                        if (xmlParser.getEventType() == XmlPullParser.END_DOCUMENT) {
-                            return;
-                        }
-                        xmlParser.next();
-                    }
-
-                    // Validates the tag is "format".
-                    if (xmlParser.getName().equals("format")) {
-                        parseFormatTag(xmlParser);
-                    } else {
-                        throw new UnsupportedOperationException("Invalid tag");
-                    }
-                    while (xmlParser.getEventType() != XmlPullParser.END_TAG) {
-                        xmlParser.next();
-                    }
-                    xmlParser.next();
-                }
-            } catch (XmlPullParserException xppe) {
-                throw new UnsupportedOperationException("Ill-formatted xml file");
-            } catch (java.io.IOException ioe) {
-                throw new UnsupportedOperationException("Unable to read xml file");
-            }
-        }
-
-        private void parseFormatTag(XmlPullParser xmlParser) {
-            String name = null;
-            String supported = null;
-            for (int i = 0; i < xmlParser.getAttributeCount(); i++) {
-                String attrName = xmlParser.getAttributeName(i);
-                if (attrName.equals("name")) {
-                    name = xmlParser.getAttributeValue(i);
-                } else if (attrName.equals("supported")) {
-                    supported = xmlParser.getAttributeValue(i);
-                } else {
-                    throw new UnsupportedOperationException("Invalid attribute name " + attrName);
-                }
-            }
-
-            if (name != null && supported != null) {
-                if (!supported.equals("true") && !supported.equals("false")) {
-                    throw new UnsupportedOperationException(
-                            ("Supported value must be either true or false"));
-                }
-                boolean isSupported = Boolean.parseBoolean(supported);
-
-                // Check if the format is already found before.
-                if (mFormatSupportedMap.get(name) != null && mFormatSupportedMap.get(name)
-                        != isSupported) {
-                    throw new UnsupportedOperationException(
-                            "Format: " + name + " has conflict supported value");
-                }
-
-                switch (name) {
-                    case "HEVC":
-                        if (isSupported) {
-                            mSupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
-                        } else {
-                            mUnsupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
-                        }
-                        break;
-                    case "VP9":
-                        if (isSupported) {
-                            mSupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_VP9);
-                        } else {
-                            mUnsupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_VP9);
-                        }
-                        break;
-                    case "AV1":
-                        if (isSupported) {
-                            mSupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_AV1);
-                        } else {
-                            mUnsupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_AV1);
-                        }
-                        break;
-                    case "HDR10":
-                        if (isSupported) {
-                            mSupportedHdrTypes.add(MediaFeature.HdrType.HDR10);
-                        } else {
-                            mUnsupportedHdrTypes.add(MediaFeature.HdrType.HDR10);
-                        }
-                        break;
-                    case "HDR10Plus":
-                        if (isSupported) {
-                            mSupportedHdrTypes.add(MediaFeature.HdrType.HDR10_PLUS);
-                        } else {
-                            mUnsupportedHdrTypes.add(MediaFeature.HdrType.HDR10_PLUS);
-                        }
-                        break;
-                    case "Dolby-Vision":
-                        if (isSupported) {
-                            mSupportedHdrTypes.add(MediaFeature.HdrType.DOLBY_VISION);
-                        } else {
-                            mUnsupportedHdrTypes.add(MediaFeature.HdrType.DOLBY_VISION);
-                        }
-                        break;
-                    case "HLG":
-                        if (isSupported) {
-                            mSupportedHdrTypes.add(MediaFeature.HdrType.HLG);
-                        } else {
-                            mUnsupportedHdrTypes.add(MediaFeature.HdrType.HLG);
-                        }
-                        break;
-                    case "SlowMotion":
-                        mIsSlowMotionSupported = isSupported;
-                        break;
-                    default:
-                        Log.w(TAG, "Invalid format name " + name);
-                }
-                // Save the name and isSupported into the map for validate later.
-                mFormatSupportedMap.put(name, isSupported);
-            } else {
-                throw new UnsupportedOperationException(
-                        "Format name and supported must both be specified");
-            }
-        }
-
-        /**
-         * Builds a {@link ApplicationMediaCapabilities} object.
-         *
-         * @return a new {@link ApplicationMediaCapabilities} instance successfully initialized
-         * with all the parameters set on this <code>Builder</code>.
-         * @throws UnsupportedOperationException if the parameters set on the
-         *                                       <code>Builder</code> were incompatible, or if they
-         *                                       are not supported by the
-         *                                       device.
-         */
-        @NonNull
-        public ApplicationMediaCapabilities build() {
-            Log.d(TAG,
-                    "Building ApplicationMediaCapabilities with: (Supported HDR: "
-                            + mSupportedHdrTypes.toString() + " Unsupported HDR: "
-                            + mUnsupportedHdrTypes.toString() + ") (Supported Codec: "
-                            + " " + mSupportedVideoMimeTypes.toString() + " Unsupported Codec:"
-                            + mUnsupportedVideoMimeTypes.toString() + ") "
-                            + mIsSlowMotionSupported);
-
-            // If hdr is supported, application must also support hevc.
-            if (!mSupportedHdrTypes.isEmpty() && !mSupportedVideoMimeTypes.contains(
-                    MediaFormat.MIMETYPE_VIDEO_HEVC)) {
-                throw new UnsupportedOperationException("Only support HEVC mime type");
-            }
-            return new ApplicationMediaCapabilities(this);
-        }
-
-        /**
-         * Adds a supported video codec mime type.
-         *
-         * @param codecMime Supported codec mime types. Must be one of the mime type defined
-         *                  in {@link MediaFormat}.
-         * @throws IllegalArgumentException if mime type is not valid.
-         */
-        @NonNull
-        public Builder addSupportedVideoMimeType(
-                @NonNull String codecMime) {
-            mSupportedVideoMimeTypes.add(codecMime);
-            return this;
-        }
-
-        private List<String> getSupportedVideoMimeTypes() {
-            return new ArrayList<>(mSupportedVideoMimeTypes);
-        }
-
-        private boolean isValidVideoCodecMimeType(@NonNull String codecMime) {
-            if (!codecMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)
-                    && !codecMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)
-                    && !codecMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AV1)) {
-                return false;
-            }
-            return true;
-        }
-
-        /**
-         * Adds an unsupported video codec mime type.
-         *
-         * @param codecMime Unsupported codec mime type. Must be one of the mime type defined
-         *                  in {@link MediaFormat}.
-         * @throws IllegalArgumentException if mime type is not valid.
-         */
-        @NonNull
-        public Builder addUnsupportedVideoMimeType(
-                @NonNull String codecMime) {
-            if (!isValidVideoCodecMimeType(codecMime)) {
-                throw new IllegalArgumentException("Invalid codec mime type: " + codecMime);
-            }
-            mUnsupportedVideoMimeTypes.add(codecMime);
-            return this;
-        }
-
-        private List<String> getUnsupportedVideoMimeTypes() {
-            return new ArrayList<>(mUnsupportedVideoMimeTypes);
-        }
-
-        /**
-         * Adds a supported hdr type.
-         *
-         * @param hdrType Supported hdr type. Must be one of the String defined in
-         *                {@link MediaFeature.HdrType}.
-         * @throws IllegalArgumentException if hdrType is not valid.
-         */
-        @NonNull
-        public Builder addSupportedHdrType(
-                @NonNull @MediaFeature.MediaHdrType String hdrType) {
-            if (!isValidVideoCodecHdrType(hdrType)) {
-                throw new IllegalArgumentException("Invalid hdr type: " + hdrType);
-            }
-            mSupportedHdrTypes.add(hdrType);
-            return this;
-        }
-
-        private List<String> getSupportedHdrTypes() {
-            return new ArrayList<>(mSupportedHdrTypes);
-        }
-
-        private boolean isValidVideoCodecHdrType(@NonNull String hdrType) {
-            if (!hdrType.equals(MediaFeature.HdrType.DOLBY_VISION)
-                    && !hdrType.equals(MediaFeature.HdrType.HDR10)
-                    && !hdrType.equals(MediaFeature.HdrType.HDR10_PLUS)
-                    && !hdrType.equals(MediaFeature.HdrType.HLG)) {
-                return false;
-            }
-            return true;
-        }
-
-        /**
-         * Adds an unsupported hdr type.
-         *
-         * @param hdrType Unsupported hdr type. Must be one of the String defined in
-         *                {@link MediaFeature.HdrType}.
-         * @throws IllegalArgumentException if hdrType is not valid.
-         */
-        @NonNull
-        public Builder addUnsupportedHdrType(
-                @NonNull @MediaFeature.MediaHdrType String hdrType) {
-            if (!isValidVideoCodecHdrType(hdrType)) {
-                throw new IllegalArgumentException("Invalid hdr type: " + hdrType);
-            }
-            mUnsupportedHdrTypes.add(hdrType);
-            return this;
-        }
-
-        private List<String> getUnsupportedHdrTypes() {
-            return new ArrayList<>(mUnsupportedHdrTypes);
-        }
-
-        /**
-         * Sets whether slow-motion video is supported.
-         * If an application indicates support for slow-motion, it is application's responsibility
-         * to parse the slow-motion videos using their own parser or using support library.
-         * @see android.media.MediaFormat#KEY_SLOW_MOTION_MARKERS
-         * @hide
-         */
-        @NonNull
-        public Builder setSlowMotionSupported(boolean slowMotionSupported) {
-            mIsSlowMotionSupported = slowMotionSupported;
-            return this;
-        }
-    }
-}
diff --git a/apex/media/framework/java/android/media/BaseMediaParceledListSlice.java b/apex/media/framework/java/android/media/BaseMediaParceledListSlice.java
deleted file mode 100644
index 915f3f6a3..0000000
--- a/apex/media/framework/java/android/media/BaseMediaParceledListSlice.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright 2020 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 android.media;
-
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This is a copied version of BaseParceledListSlice in framework with hidden API usages
- * removed.
- *
- * Transfer a large list of Parcelable objects across an IPC.  Splits into
- * multiple transactions if needed.
- *
- * Caveat: for efficiency and security, all elements must be the same concrete type.
- * In order to avoid writing the class name of each object, we must ensure that
- * each object is the same type, or else unparceling then reparceling the data may yield
- * a different result if the class name encoded in the Parcelable is a Base type.
- * See b/17671747.
- *
- * @hide
- */
-abstract class BaseMediaParceledListSlice<T> implements Parcelable {
-    private static String TAG = "BaseMediaParceledListSlice";
-    private static final boolean DEBUG = false;
-
-    /*
-     * TODO get this number from somewhere else. For now set it to a quarter of
-     * the 1MB limit.
-     */
-    // private static final int MAX_IPC_SIZE = IBinder.getSuggestedMaxIpcSizeBytes();
-    private static final int MAX_IPC_SIZE = 64 * 1024;
-
-    private final List<T> mList;
-
-    private int mInlineCountLimit = Integer.MAX_VALUE;
-
-    public BaseMediaParceledListSlice(List<T> list) {
-        mList = list;
-    }
-
-    @SuppressWarnings("unchecked")
-    BaseMediaParceledListSlice(Parcel p, ClassLoader loader) {
-        final int N = p.readInt();
-        mList = new ArrayList<T>(N);
-        if (DEBUG) Log.d(TAG, "Retrieving " + N + " items");
-        if (N <= 0) {
-            return;
-        }
-
-        Parcelable.Creator<?> creator = readParcelableCreator(p, loader);
-        Class<?> listElementClass = null;
-
-        int i = 0;
-        while (i < N) {
-            if (p.readInt() == 0) {
-                break;
-            }
-
-            final T parcelable = readCreator(creator, p, loader);
-            if (listElementClass == null) {
-                listElementClass = parcelable.getClass();
-            } else {
-                verifySameType(listElementClass, parcelable.getClass());
-            }
-
-            mList.add(parcelable);
-
-            if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1));
-            i++;
-        }
-        if (i >= N) {
-            return;
-        }
-        final IBinder retriever = p.readStrongBinder();
-        while (i < N) {
-            if (DEBUG) Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever);
-            Parcel data = Parcel.obtain();
-            Parcel reply = Parcel.obtain();
-            data.writeInt(i);
-            try {
-                retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e);
-                return;
-            }
-            while (i < N && reply.readInt() != 0) {
-                final T parcelable = readCreator(creator, reply, loader);
-                verifySameType(listElementClass, parcelable.getClass());
-
-                mList.add(parcelable);
-
-                if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1));
-                i++;
-            }
-            reply.recycle();
-            data.recycle();
-        }
-    }
-
-    private T readCreator(Parcelable.Creator<?> creator, Parcel p, ClassLoader loader) {
-        if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
-            Parcelable.ClassLoaderCreator<?> classLoaderCreator =
-                    (Parcelable.ClassLoaderCreator<?>) creator;
-            return (T) classLoaderCreator.createFromParcel(p, loader);
-        }
-        return (T) creator.createFromParcel(p);
-    }
-
-    private static void verifySameType(final Class<?> expected, final Class<?> actual) {
-        if (!actual.equals(expected)) {
-            throw new IllegalArgumentException("Can't unparcel type "
-                    + (actual == null ? null : actual.getName()) + " in list of type "
-                    + (expected == null ? null : expected.getName()));
-        }
-    }
-
-    public List<T> getList() {
-        return mList;
-    }
-
-    /**
-     * Set a limit on the maximum number of entries in the array that will be included
-     * inline in the initial parcelling of this object.
-     */
-    public void setInlineCountLimit(int maxCount) {
-        mInlineCountLimit = maxCount;
-    }
-
-    /**
-     * Write this to another Parcel. Note that this discards the internal Parcel
-     * and should not be used anymore. This is so we can pass this to a Binder
-     * where we won't have a chance to call recycle on this.
-     */
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        final int N = mList.size();
-        final int callFlags = flags;
-        dest.writeInt(N);
-        if (DEBUG) Log.d(TAG, "Writing " + N + " items");
-        if (N > 0) {
-            final Class<?> listElementClass = mList.get(0).getClass();
-            writeParcelableCreator(mList.get(0), dest);
-            int i = 0;
-            while (i < N && i < mInlineCountLimit && dest.dataSize() < MAX_IPC_SIZE) {
-                dest.writeInt(1);
-
-                final T parcelable = mList.get(i);
-                verifySameType(listElementClass, parcelable.getClass());
-                writeElement(parcelable, dest, callFlags);
-
-                if (DEBUG) Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
-                i++;
-            }
-            if (i < N) {
-                dest.writeInt(0);
-                Binder retriever = new Binder() {
-                    @Override
-                    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
-                            throws RemoteException {
-                        if (code != FIRST_CALL_TRANSACTION) {
-                            return super.onTransact(code, data, reply, flags);
-                        }
-                        int i = data.readInt();
-                        if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N);
-                        while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
-                            reply.writeInt(1);
-
-                            final T parcelable = mList.get(i);
-                            verifySameType(listElementClass, parcelable.getClass());
-                            writeElement(parcelable, reply, callFlags);
-
-                            if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
-                            i++;
-                        }
-                        if (i < N) {
-                            if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N);
-                            reply.writeInt(0);
-                        }
-                        return true;
-                    }
-                };
-                if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N + ": retriever=" + retriever);
-                dest.writeStrongBinder(retriever);
-            }
-        }
-    }
-
-    abstract void writeElement(T parcelable, Parcel reply, int callFlags);
-
-    abstract void writeParcelableCreator(T parcelable, Parcel dest);
-
-    abstract Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader);
-}
diff --git a/apex/media/framework/java/android/media/BufferingParams.java b/apex/media/framework/java/android/media/BufferingParams.java
deleted file mode 100644
index 04af028..0000000
--- a/apex/media/framework/java/android/media/BufferingParams.java
+++ /dev/null
@@ -1,188 +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.
- */
-
-package android.media;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Structure for source buffering management params.
- *
- * Used by {@link MediaPlayer#getBufferingParams()} and
- * {@link MediaPlayer#setBufferingParams(BufferingParams)}
- * to control source buffering behavior.
- *
- * <p>There are two stages of source buffering in {@link MediaPlayer}: initial buffering
- * (when {@link MediaPlayer} is being prepared) and rebuffering (when {@link MediaPlayer}
- * is playing back source). {@link BufferingParams} includes corresponding marks for each
- * stage of source buffering. The marks are time based (in milliseconds).
- *
- * <p>{@link MediaPlayer} source component has default marks which can be queried by
- * calling {@link MediaPlayer#getBufferingParams()} before any change is made by
- * {@link MediaPlayer#setBufferingParams()}.
- * <ul>
- * <li><strong>initial buffering:</strong> initialMarkMs is used when
- * {@link MediaPlayer} is being prepared. When cached data amount exceeds this mark
- * {@link MediaPlayer} is prepared. </li>
- * <li><strong>rebuffering during playback:</strong> resumePlaybackMarkMs is used when
- * {@link MediaPlayer} is playing back content.
- * <ul>
- * <li> {@link MediaPlayer} has internal mark, namely pausePlaybackMarkMs, to decide when
- * to pause playback if cached data amount runs low. This internal mark varies based on
- * type of data source. </li>
- * <li> When cached data amount exceeds resumePlaybackMarkMs, {@link MediaPlayer} will
- * resume playback if it has been paused due to low cached data amount. The internal mark
- * pausePlaybackMarkMs shall be less than resumePlaybackMarkMs. </li>
- * <li> {@link MediaPlayer} has internal mark, namely pauseRebufferingMarkMs, to decide
- * when to pause rebuffering. Apparently, this internal mark shall be no less than
- * resumePlaybackMarkMs. </li>
- * <li> {@link MediaPlayer} has internal mark, namely resumeRebufferingMarkMs, to decide
- * when to resume buffering. This internal mark varies based on type of data source. This
- * mark shall be larger than pausePlaybackMarkMs, and less than pauseRebufferingMarkMs.
- * </li>
- * </ul> </li>
- * </ul>
- * <p>Users should use {@link Builder} to change {@link BufferingParams}.
- * @hide
- */
-public final class BufferingParams implements Parcelable {
-    private static final int BUFFERING_NO_MARK = -1;
-
-    // params
-    private int mInitialMarkMs = BUFFERING_NO_MARK;
-
-    private int mResumePlaybackMarkMs = BUFFERING_NO_MARK;
-
-    private BufferingParams() {
-    }
-
-    /**
-     * Return initial buffering mark in milliseconds.
-     * @return initial buffering mark in milliseconds
-     */
-    public int getInitialMarkMs() {
-        return mInitialMarkMs;
-    }
-
-    /**
-     * Return the mark in milliseconds for resuming playback.
-     * @return the mark for resuming playback in milliseconds
-     */
-    public int getResumePlaybackMarkMs() {
-        return mResumePlaybackMarkMs;
-    }
-
-    /**
-     * Builder class for {@link BufferingParams} objects.
-     * <p> Here is an example where <code>Builder</code> is used to define the
-     * {@link BufferingParams} to be used by a {@link MediaPlayer} instance:
-     *
-     * <pre class="prettyprint">
-     * BufferingParams myParams = mediaplayer.getDefaultBufferingParams();
-     * myParams = new BufferingParams.Builder(myParams)
-     *         .setInitialMarkMs(10000)
-     *         .setResumePlaybackMarkMs(15000)
-     *         .build();
-     * mediaplayer.setBufferingParams(myParams);
-     * </pre>
-     */
-    public static class Builder {
-        private int mInitialMarkMs = BUFFERING_NO_MARK;
-        private int mResumePlaybackMarkMs = BUFFERING_NO_MARK;
-
-        /**
-         * Constructs a new Builder with the defaults.
-         * By default, all marks are -1.
-         */
-        public Builder() {
-        }
-
-        /**
-         * Constructs a new Builder from a given {@link BufferingParams} instance
-         * @param bp the {@link BufferingParams} object whose data will be reused
-         * in the new Builder.
-         */
-        public Builder(BufferingParams bp) {
-            mInitialMarkMs = bp.mInitialMarkMs;
-            mResumePlaybackMarkMs = bp.mResumePlaybackMarkMs;
-        }
-
-        /**
-         * Combines all of the fields that have been set and return a new
-         * {@link BufferingParams} object. <code>IllegalStateException</code> will be
-         * thrown if there is conflict between fields.
-         * @return a new {@link BufferingParams} object
-         */
-        public BufferingParams build() {
-            BufferingParams bp = new BufferingParams();
-            bp.mInitialMarkMs = mInitialMarkMs;
-            bp.mResumePlaybackMarkMs = mResumePlaybackMarkMs;
-
-            return bp;
-        }
-
-        /**
-         * Sets the time based mark in milliseconds for initial buffering.
-         * @param markMs time based mark in milliseconds
-         * @return the same Builder instance.
-         */
-        public Builder setInitialMarkMs(int markMs) {
-            mInitialMarkMs = markMs;
-            return this;
-        }
-
-        /**
-         * Sets the time based mark in milliseconds for resuming playback.
-         * @param markMs time based mark in milliseconds for resuming playback
-         * @return the same Builder instance.
-         */
-        public Builder setResumePlaybackMarkMs(int markMs) {
-            mResumePlaybackMarkMs = markMs;
-            return this;
-        }
-    }
-
-    private BufferingParams(Parcel in) {
-        mInitialMarkMs = in.readInt();
-        mResumePlaybackMarkMs = in.readInt();
-    }
-
-    public static final @android.annotation.NonNull Parcelable.Creator<BufferingParams> CREATOR =
-            new Parcelable.Creator<BufferingParams>() {
-                @Override
-                public BufferingParams createFromParcel(Parcel in) {
-                    return new BufferingParams(in);
-                }
-
-                @Override
-                public BufferingParams[] newArray(int size) {
-                    return new BufferingParams[size];
-                }
-            };
-
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mInitialMarkMs);
-        dest.writeInt(mResumePlaybackMarkMs);
-    }
-}
diff --git a/apex/media/framework/java/android/media/Controller2Link.java b/apex/media/framework/java/android/media/Controller2Link.java
deleted file mode 100644
index 8eefec7..0000000
--- a/apex/media/framework/java/android/media/Controller2Link.java
+++ /dev/null
@@ -1,216 +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 android.media;
-
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-
-import java.util.Objects;
-
-/**
- * Handles incoming commands from {@link MediaSession2} to {@link MediaController2}.
- * @hide
- */
-// @SystemApi
-public final class Controller2Link implements Parcelable {
-    private static final String TAG = "Controller2Link";
-    private static final boolean DEBUG = MediaController2.DEBUG;
-
-    public static final @android.annotation.NonNull Parcelable.Creator<Controller2Link> CREATOR =
-            new Parcelable.Creator<Controller2Link>() {
-                @Override
-                public Controller2Link createFromParcel(Parcel in) {
-                    return new Controller2Link(in);
-                }
-
-                @Override
-                public Controller2Link[] newArray(int size) {
-                    return new Controller2Link[size];
-                }
-            };
-
-
-    private final MediaController2 mController;
-    private final IMediaController2 mIController;
-
-    public Controller2Link(MediaController2 controller) {
-        mController = controller;
-        mIController = new Controller2Stub();
-    }
-
-    Controller2Link(Parcel in) {
-        mController = null;
-        mIController = IMediaController2.Stub.asInterface(in.readStrongBinder());
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStrongBinder(mIController.asBinder());
-    }
-
-    @Override
-    public int hashCode() {
-        return mIController.asBinder().hashCode();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof Controller2Link)) {
-            return false;
-        }
-        Controller2Link other = (Controller2Link) obj;
-        return Objects.equals(mIController.asBinder(), other.mIController.asBinder());
-    }
-
-    /** Interface method for IMediaController2.notifyConnected */
-    public void notifyConnected(int seq, Bundle connectionResult) {
-        try {
-            mIController.notifyConnected(seq, connectionResult);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for IMediaController2.notifyDisonnected */
-    public void notifyDisconnected(int seq) {
-        try {
-            mIController.notifyDisconnected(seq);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for IMediaController2.notifyPlaybackActiveChanged */
-    public void notifyPlaybackActiveChanged(int seq, boolean playbackActive) {
-        try {
-            mIController.notifyPlaybackActiveChanged(seq, playbackActive);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for IMediaController2.sendSessionCommand */
-    public void sendSessionCommand(int seq, Session2Command command, Bundle args,
-            ResultReceiver resultReceiver) {
-        try {
-            mIController.sendSessionCommand(seq, command, args, resultReceiver);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for IMediaController2.cancelSessionCommand */
-    public void cancelSessionCommand(int seq) {
-        try {
-            mIController.cancelSessionCommand(seq);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Stub implementation for IMediaController2.notifyConnected */
-    public void onConnected(int seq, Bundle connectionResult) {
-        if (connectionResult == null) {
-            onDisconnected(seq);
-            return;
-        }
-        mController.onConnected(seq, connectionResult);
-    }
-
-    /** Stub implementation for IMediaController2.notifyDisonnected */
-    public void onDisconnected(int seq) {
-        mController.onDisconnected(seq);
-    }
-
-    /** Stub implementation for IMediaController2.notifyPlaybackActiveChanged */
-    public void onPlaybackActiveChanged(int seq, boolean playbackActive) {
-        mController.onPlaybackActiveChanged(seq, playbackActive);
-    }
-
-    /** Stub implementation for IMediaController2.sendSessionCommand */
-    public void onSessionCommand(int seq, Session2Command command, Bundle args,
-            ResultReceiver resultReceiver) {
-        mController.onSessionCommand(seq, command, args, resultReceiver);
-    }
-
-    /** Stub implementation for IMediaController2.cancelSessionCommand */
-    public void onCancelCommand(int seq) {
-        mController.onCancelCommand(seq);
-    }
-
-    private class Controller2Stub extends IMediaController2.Stub {
-        @Override
-        public void notifyConnected(int seq, Bundle connectionResult) {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                Controller2Link.this.onConnected(seq, connectionResult);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void notifyDisconnected(int seq) {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                Controller2Link.this.onDisconnected(seq);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void notifyPlaybackActiveChanged(int seq, boolean playbackActive) {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                Controller2Link.this.onPlaybackActiveChanged(seq, playbackActive);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void sendSessionCommand(int seq, Session2Command command, Bundle args,
-                ResultReceiver resultReceiver) {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                Controller2Link.this.onSessionCommand(seq, command, args, resultReceiver);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void cancelSessionCommand(int seq) {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                Controller2Link.this.onCancelCommand(seq);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-    }
-}
diff --git a/apex/media/framework/java/android/media/DataSourceCallback.java b/apex/media/framework/java/android/media/DataSourceCallback.java
deleted file mode 100644
index c297ecd..0000000
--- a/apex/media/framework/java/android/media/DataSourceCallback.java
+++ /dev/null
@@ -1,68 +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.
- */
-
-
-package android.media;
-
-import android.annotation.NonNull;
-
-import java.io.Closeable;
-import java.io.IOException;
-
-/**
- * For supplying media data to the framework. Implement this if your app has
- * special requirements for the way media data is obtained.
- *
- * <p class="note">Methods of this interface may be called on multiple different
- * threads. There will be a thread synchronization point between each call to ensure that
- * modifications to the state of your DataSourceCallback are visible to future calls. This means
- * you don't need to do your own synchronization unless you're modifying the
- * DataSourceCallback from another thread while it's being used by the framework.</p>
- *
- * @hide
- */
-public abstract class DataSourceCallback implements Closeable {
-
-    public static final int END_OF_STREAM = -1;
-
-    /**
-     * Called to request data from the given position.
-     *
-     * Implementations should should write up to {@code size} bytes into
-     * {@code buffer}, and return the number of bytes written.
-     *
-     * Return {@code 0} if size is zero (thus no bytes are read).
-     *
-     * Return {@code -1} to indicate that end of stream is reached.
-     *
-     * @param position the position in the data source to read from.
-     * @param buffer the buffer to read the data into.
-     * @param offset the offset within buffer to read the data into.
-     * @param size the number of bytes to read.
-     * @throws IOException on fatal errors.
-     * @return the number of bytes read, or {@link #END_OF_STREAM} if end of stream is reached.
-     */
-    public abstract int readAt(long position, @NonNull byte[] buffer, int offset, int size)
-            throws IOException;
-
-    /**
-     * Called to get the size of the data source.
-     *
-     * @throws IOException on fatal errors
-     * @return the size of data source in bytes, or -1 if the size is unknown.
-     */
-    public abstract long getSize() throws IOException;
-}
diff --git a/apex/media/framework/java/android/media/MediaCommunicationManager.java b/apex/media/framework/java/android/media/MediaCommunicationManager.java
deleted file mode 100644
index ef5552e..0000000
--- a/apex/media/framework/java/android/media/MediaCommunicationManager.java
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * Copyright 2020 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 android.media;
-
-import static android.Manifest.permission.MEDIA_CONTENT_CONTROL;
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-
-import android.annotation.CallbackExecutor;
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.annotation.SystemService;
-import android.content.Context;
-import android.media.session.MediaSession;
-import android.media.session.MediaSessionManager;
-import android.os.Build;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.service.media.MediaBrowserService;
-import android.util.Log;
-import android.view.KeyEvent;
-
-import androidx.annotation.RequiresApi;
-
-import androidx.annotation.RequiresApi;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.modules.annotation.MinSdk;
-import com.android.modules.utils.build.SdkLevel;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.Executor;
-
-/**
- * Provides support for interacting with {@link android.media.MediaSession2 MediaSession2s}
- * that applications have published to express their ongoing media playback state.
- */
-@MinSdk(Build.VERSION_CODES.S)
-@RequiresApi(Build.VERSION_CODES.S)
-@SystemService(Context.MEDIA_COMMUNICATION_SERVICE)
-public class MediaCommunicationManager {
-    private static final String TAG = "MediaCommunicationManager";
-
-    /**
-     * The manager version used from beginning.
-     */
-    private static final int VERSION_1 = 1;
-
-    /**
-     * Current manager version.
-     */
-    private static final int CURRENT_VERSION = VERSION_1;
-
-    private final Context mContext;
-    // Do not access directly use getService().
-    private IMediaCommunicationService mService;
-
-    private final Object mLock = new Object();
-    private final CopyOnWriteArrayList<SessionCallbackRecord> mTokenCallbackRecords =
-            new CopyOnWriteArrayList<>();
-
-    @GuardedBy("mLock")
-    private MediaCommunicationServiceCallbackStub mCallbackStub;
-
-    // TODO: remove this when MCS implements dispatchMediaKeyEvent.
-    private MediaSessionManager mMediaSessionManager;
-
-    /**
-     * @hide
-     */
-    public MediaCommunicationManager(@NonNull Context context) {
-        if (!SdkLevel.isAtLeastS()) {
-            throw new UnsupportedOperationException("Android version must be S or greater.");
-        }
-        mContext = context;
-    }
-
-    /**
-     * Gets the version of this {@link MediaCommunicationManager}.
-     */
-    public @IntRange(from = 1) int getVersion() {
-        return CURRENT_VERSION;
-    }
-
-    /**
-     * Notifies that a new {@link MediaSession2} with type {@link Session2Token#TYPE_SESSION} is
-     * created.
-     * @param token newly created session2 token
-     * @hide
-     */
-    public void notifySession2Created(@NonNull Session2Token token) {
-        Objects.requireNonNull(token, "token shouldn't be null");
-        if (token.getType() != Session2Token.TYPE_SESSION) {
-            throw new IllegalArgumentException("token's type should be TYPE_SESSION");
-        }
-        try {
-            getService().notifySession2Created(token);
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Checks whether the remote user is a trusted app.
-     * <p>
-     * An app is trusted if the app holds the
-     * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission or has an enabled
-     * notification listener.
-     *
-     * @param userInfo The remote user info from either
-     *            {@link MediaSession#getCurrentControllerInfo()} or
-     *            {@link MediaBrowserService#getCurrentBrowserInfo()}.
-     * @return {@code true} if the remote user is trusted or {@code false} otherwise.
-     * @hide
-     */
-    public boolean isTrustedForMediaControl(@NonNull MediaSessionManager.RemoteUserInfo userInfo) {
-        Objects.requireNonNull(userInfo, "userInfo shouldn't be null");
-        if (userInfo.getPackageName() == null) {
-            return false;
-        }
-        try {
-            return getService().isTrusted(
-                    userInfo.getPackageName(), userInfo.getPid(), userInfo.getUid());
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot communicate with the service.", e);
-        }
-        return false;
-    }
-
-    /**
-     * This API is not generally intended for third party application developers.
-     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
-     * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
-     * Library</a> for consistent behavior across all devices.
-     * <p>
-     * Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the
-     * current user.
-     * <p>
-     * Although this API can be used without any restriction, each session owners can accept or
-     * reject your uses of {@link MediaSession2}.
-     *
-     * @return A list of {@link Session2Token}.
-     */
-    @NonNull
-    public List<Session2Token> getSession2Tokens() {
-        return getSession2Tokens(UserHandle.myUserId());
-    }
-
-    /**
-     * Adds a callback to be notified when the list of active sessions changes.
-     * <p>
-     * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be
-     * held by the calling app.
-     * </p>
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    @RequiresPermission(MEDIA_CONTENT_CONTROL)
-    public void registerSessionCallback(@CallbackExecutor @NonNull Executor executor,
-            @NonNull SessionCallback callback) {
-        Objects.requireNonNull(executor, "executor must not be null");
-        Objects.requireNonNull(callback, "callback must not be null");
-
-        if (!mTokenCallbackRecords.addIfAbsent(
-                new SessionCallbackRecord(executor, callback))) {
-            Log.w(TAG, "registerSession2TokenCallback: Ignoring the same callback");
-            return;
-        }
-        synchronized (mLock) {
-            if (mCallbackStub == null) {
-                MediaCommunicationServiceCallbackStub callbackStub =
-                        new MediaCommunicationServiceCallbackStub();
-                try {
-                    getService().registerCallback(callbackStub, mContext.getPackageName());
-                    mCallbackStub = callbackStub;
-                } catch (RemoteException ex) {
-                    Log.e(TAG, "Failed to register callback.", ex);
-                }
-            }
-        }
-    }
-
-    /**
-     * Stops receiving active sessions updates on the specified callback.
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public void unregisterSessionCallback(@NonNull SessionCallback callback) {
-        if (!mTokenCallbackRecords.remove(
-                new SessionCallbackRecord(null, callback))) {
-            Log.w(TAG, "unregisterSession2TokenCallback: Ignoring an unknown callback.");
-            return;
-        }
-        synchronized (mLock) {
-            if (mCallbackStub != null && mTokenCallbackRecords.isEmpty()) {
-                try {
-                    getService().unregisterCallback(mCallbackStub);
-                } catch (RemoteException ex) {
-                    Log.e(TAG, "Failed to unregister callback.", ex);
-                }
-                mCallbackStub = null;
-            }
-        }
-    }
-
-    private IMediaCommunicationService getService() {
-        if (mService == null) {
-            mService = IMediaCommunicationService.Stub.asInterface(
-                    MediaFrameworkInitializer.getMediaServiceManager()
-                            .getMediaCommunicationServiceRegisterer()
-                            .get());
-        }
-        return mService;
-    }
-
-    // TODO: remove this when MCS implements dispatchMediaKeyEvent.
-    private MediaSessionManager getMediaSessionManager() {
-        if (mMediaSessionManager == null) {
-            mMediaSessionManager = mContext.getSystemService(MediaSessionManager.class);
-        }
-        return mMediaSessionManager;
-    }
-
-    private List<Session2Token> getSession2Tokens(int userId) {
-        try {
-            MediaParceledListSlice slice = getService().getSession2Tokens(userId);
-            return slice == null ? Collections.emptyList() : slice.getList();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to get session tokens", e);
-        }
-        return Collections.emptyList();
-    }
-
-    /**
-     * Sends a media key event. The receiver will be selected automatically.
-     *
-     * @param keyEvent the key event to send
-     * @param asSystemService if {@code true}, the event sent to the session as if it was come from
-     *                        the system service instead of the app process.
-     * @hide
-     */
-    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-    public void dispatchMediaKeyEvent(@NonNull KeyEvent keyEvent, boolean asSystemService) {
-        Objects.requireNonNull(keyEvent, "keyEvent shouldn't be null");
-
-        // When MCS handles this, caller is changed.
-        // TODO: remove this when MCS implementation is done.
-        if (!asSystemService) {
-            getMediaSessionManager().dispatchMediaKeyEvent(keyEvent, false);
-            return;
-        }
-
-        try {
-            getService().dispatchMediaKeyEvent(mContext.getPackageName(),
-                    keyEvent, asSystemService);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to send key event.", e);
-        }
-    }
-
-    /**
-     * Callback for listening to changes to the sessions.
-     * @see #registerSessionCallback(Executor, SessionCallback)
-     * @hide
-     */
-    @SystemApi(client = MODULE_LIBRARIES)
-    public interface SessionCallback {
-        /**
-         * Called when a new {@link MediaSession2 media session2} is created.
-         * @param token the newly created token
-         */
-        default void onSession2TokenCreated(@NonNull Session2Token token) {}
-
-        /**
-         * Called when {@link #getSession2Tokens() session tokens} are changed.
-         */
-        default void onSession2TokensChanged(@NonNull List<Session2Token> tokens) {}
-    }
-
-    private static final class SessionCallbackRecord {
-        public final Executor executor;
-        public final SessionCallback callback;
-
-        SessionCallbackRecord(Executor executor, SessionCallback callback) {
-            this.executor = executor;
-            this.callback = callback;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(callback);
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (!(obj instanceof SessionCallbackRecord)) {
-                return false;
-            }
-            return Objects.equals(this.callback, ((SessionCallbackRecord) obj).callback);
-        }
-    }
-
-    class MediaCommunicationServiceCallbackStub extends IMediaCommunicationServiceCallback.Stub {
-        @Override
-        public void onSession2Created(Session2Token token) throws RemoteException {
-            for (SessionCallbackRecord record : mTokenCallbackRecords) {
-                record.executor.execute(() -> record.callback.onSession2TokenCreated(token));
-            }
-        }
-
-        @Override
-        public void onSession2Changed(MediaParceledListSlice tokens) throws RemoteException {
-            List<Session2Token> tokenList = tokens.getList();
-            for (SessionCallbackRecord record : mTokenCallbackRecords) {
-                record.executor.execute(() -> record.callback.onSession2TokensChanged(tokenList));
-            }
-        }
-    }
-}
diff --git a/apex/media/framework/java/android/media/MediaConstants.java b/apex/media/framework/java/android/media/MediaConstants.java
deleted file mode 100644
index ce10889..0000000
--- a/apex/media/framework/java/android/media/MediaConstants.java
+++ /dev/null
@@ -1,35 +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 android.media;
-
-class MediaConstants {
-    // Bundle key for int
-    static final String KEY_PID = "android.media.key.PID";
-
-    // Bundle key for String
-    static final String KEY_PACKAGE_NAME = "android.media.key.PACKAGE_NAME";
-
-    // Bundle key for Parcelable
-    static final String KEY_SESSION2LINK = "android.media.key.SESSION2LINK";
-    static final String KEY_ALLOWED_COMMANDS = "android.media.key.ALLOWED_COMMANDS";
-    static final String KEY_PLAYBACK_ACTIVE = "android.media.key.PLAYBACK_ACTIVE";
-    static final String KEY_TOKEN_EXTRAS = "android.media.key.TOKEN_EXTRAS";
-    static final String KEY_CONNECTION_HINTS = "android.media.key.CONNECTION_HINTS";
-
-    private MediaConstants() {
-    }
-}
diff --git a/apex/media/framework/java/android/media/MediaController2.java b/apex/media/framework/java/android/media/MediaController2.java
deleted file mode 100644
index 159e8e5..0000000
--- a/apex/media/framework/java/android/media/MediaController2.java
+++ /dev/null
@@ -1,637 +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 android.media;
-
-import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS;
-import static android.media.MediaConstants.KEY_CONNECTION_HINTS;
-import static android.media.MediaConstants.KEY_PACKAGE_NAME;
-import static android.media.MediaConstants.KEY_PID;
-import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE;
-import static android.media.MediaConstants.KEY_SESSION2LINK;
-import static android.media.MediaConstants.KEY_TOKEN_EXTRAS;
-import static android.media.Session2Command.Result.RESULT_ERROR_UNKNOWN_ERROR;
-import static android.media.Session2Command.Result.RESULT_INFO_SKIPPED;
-import static android.media.Session2Token.TYPE_SESSION;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-
-import java.util.concurrent.Executor;
-
-/**
- * This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
- * Library</a> for consistent behavior across all devices.
- *
- * Allows an app to interact with an active {@link MediaSession2} or a
- * {@link MediaSession2Service} which would provide {@link MediaSession2}. Media buttons and other
- * commands can be sent to the session.
- */
-public class MediaController2 implements AutoCloseable {
-    static final String TAG = "MediaController2";
-    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final ControllerCallback mCallback;
-
-    private final IBinder.DeathRecipient mDeathRecipient = () -> close();
-    private final Context mContext;
-    private final Session2Token mSessionToken;
-    private final Executor mCallbackExecutor;
-    private final Controller2Link mControllerStub;
-    private final Handler mResultHandler;
-    private final SessionServiceConnection mServiceConnection;
-
-    private final Object mLock = new Object();
-    //@GuardedBy("mLock")
-    private boolean mClosed;
-    //@GuardedBy("mLock")
-    private int mNextSeqNumber;
-    //@GuardedBy("mLock")
-    private Session2Link mSessionBinder;
-    //@GuardedBy("mLock")
-    private Session2CommandGroup mAllowedCommands;
-    //@GuardedBy("mLock")
-    private Session2Token mConnectedToken;
-    //@GuardedBy("mLock")
-    private ArrayMap<ResultReceiver, Integer> mPendingCommands;
-    //@GuardedBy("mLock")
-    private ArraySet<Integer> mRequestedCommandSeqNumbers;
-    //@GuardedBy("mLock")
-    private boolean mPlaybackActive;
-
-    /**
-     * Create a {@link MediaController2} from the {@link Session2Token}.
-     * This connects to the session and may wake up the service if it's not available.
-     *
-     * @param context context
-     * @param token token to connect to
-     * @param connectionHints a session-specific argument to send to the session when connecting.
-     *                        The contents of this bundle may affect the connection result.
-     * @param executor executor to run callbacks on.
-     * @param callback controller callback to receive changes in.
-     */
-    MediaController2(@NonNull Context context, @NonNull Session2Token token,
-            @NonNull Bundle connectionHints, @NonNull Executor executor,
-            @NonNull ControllerCallback callback) {
-        if (context == null) {
-            throw new IllegalArgumentException("context shouldn't be null");
-        }
-        if (token == null) {
-            throw new IllegalArgumentException("token shouldn't be null");
-        }
-        mContext = context;
-        mSessionToken = token;
-        mCallbackExecutor = (executor == null) ? context.getMainExecutor() : executor;
-        mCallback = (callback == null) ? new ControllerCallback() {} : callback;
-        mControllerStub = new Controller2Link(this);
-        // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
-        mResultHandler = new Handler(context.getMainLooper());
-
-        mNextSeqNumber = 0;
-        mPendingCommands = new ArrayMap<>();
-        mRequestedCommandSeqNumbers = new ArraySet<>();
-
-        boolean connectRequested;
-        if (token.getType() == TYPE_SESSION) {
-            mServiceConnection = null;
-            connectRequested = requestConnectToSession(connectionHints);
-        } else {
-            mServiceConnection = new SessionServiceConnection(connectionHints);
-            connectRequested = requestConnectToService();
-        }
-        if (!connectRequested) {
-            close();
-        }
-    }
-
-    @Override
-    public void close() {
-        synchronized (mLock) {
-            if (mClosed) {
-                // Already closed. Ignore rest of clean up code.
-                // Note: unbindService() throws IllegalArgumentException when it's called twice.
-                return;
-            }
-            if (DEBUG) {
-                Log.d(TAG, "closing " + this);
-            }
-            mClosed = true;
-            if (mServiceConnection != null) {
-                // Note: This should be called even when the bindService() has returned false.
-                mContext.unbindService(mServiceConnection);
-            }
-            if (mSessionBinder != null) {
-                try {
-                    mSessionBinder.disconnect(mControllerStub, getNextSeqNumber());
-                    mSessionBinder.unlinkToDeath(mDeathRecipient, 0);
-                } catch (RuntimeException e) {
-                    // No-op
-                }
-            }
-            mConnectedToken = null;
-            mPendingCommands.clear();
-            mRequestedCommandSeqNumbers.clear();
-            mCallbackExecutor.execute(() -> {
-                mCallback.onDisconnected(MediaController2.this);
-            });
-            mSessionBinder = null;
-        }
-    }
-
-    /**
-     * Returns {@link Session2Token} of the connected session.
-     * If it is not connected yet, it returns {@code null}.
-     * <p>
-     * This may differ with the {@link Session2Token} from the constructor. For example, if the
-     * controller is created with the token for {@link MediaSession2Service}, this would return
-     * token for the {@link MediaSession2} in the service.
-     *
-     * @return Session2Token of the connected session, or {@code null} if not connected
-     */
-    @Nullable
-    public Session2Token getConnectedToken() {
-        synchronized (mLock) {
-            return mConnectedToken;
-        }
-    }
-
-    /**
-     * Returns whether the session's playback is active.
-     *
-     * @return {@code true} if playback active. {@code false} otherwise.
-     * @see ControllerCallback#onPlaybackActiveChanged(MediaController2, boolean)
-     */
-    public boolean isPlaybackActive() {
-        synchronized (mLock) {
-            return mPlaybackActive;
-        }
-    }
-
-    /**
-     * Sends a session command to the session
-     * <p>
-     * @param command the session command
-     * @param args optional arguments
-     * @return a token which will be sent together in {@link ControllerCallback#onCommandResult}
-     *        when its result is received.
-     */
-    @NonNull
-    public Object sendSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) {
-        if (command == null) {
-            throw new IllegalArgumentException("command shouldn't be null");
-        }
-
-        ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) {
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                synchronized (mLock) {
-                    mPendingCommands.remove(this);
-                }
-                mCallbackExecutor.execute(() -> {
-                    mCallback.onCommandResult(MediaController2.this, this,
-                            command, new Session2Command.Result(resultCode, resultData));
-                });
-            }
-        };
-
-        synchronized (mLock) {
-            if (mSessionBinder != null) {
-                int seq = getNextSeqNumber();
-                mPendingCommands.put(resultReceiver, seq);
-                try {
-                    mSessionBinder.sendSessionCommand(mControllerStub, seq, command, args,
-                            resultReceiver);
-                } catch (RuntimeException e)  {
-                    mPendingCommands.remove(resultReceiver);
-                    resultReceiver.send(RESULT_ERROR_UNKNOWN_ERROR, null);
-                }
-            }
-        }
-        return resultReceiver;
-    }
-
-    /**
-     * Cancels the session command previously sent.
-     *
-     * @param token the token which is returned from {@link #sendSessionCommand}.
-     */
-    public void cancelSessionCommand(@NonNull Object token) {
-        if (token == null) {
-            throw new IllegalArgumentException("token shouldn't be null");
-        }
-        synchronized (mLock) {
-            if (mSessionBinder == null) return;
-            Integer seq = mPendingCommands.remove(token);
-            if (seq != null) {
-                mSessionBinder.cancelSessionCommand(mControllerStub, seq);
-            }
-        }
-    }
-
-    // Called by Controller2Link.onConnected
-    void onConnected(int seq, Bundle connectionResult) {
-        Session2Link sessionBinder = connectionResult.getParcelable(KEY_SESSION2LINK);
-        Session2CommandGroup allowedCommands =
-                connectionResult.getParcelable(KEY_ALLOWED_COMMANDS);
-        boolean playbackActive = connectionResult.getBoolean(KEY_PLAYBACK_ACTIVE);
-
-        Bundle tokenExtras = connectionResult.getBundle(KEY_TOKEN_EXTRAS);
-        if (tokenExtras == null) {
-            Log.w(TAG, "extras shouldn't be null.");
-            tokenExtras = Bundle.EMPTY;
-        } else if (MediaSession2.hasCustomParcelable(tokenExtras)) {
-            Log.w(TAG, "extras contain custom parcelable. Ignoring.");
-            tokenExtras = Bundle.EMPTY;
-        }
-
-        if (DEBUG) {
-            Log.d(TAG, "notifyConnected sessionBinder=" + sessionBinder
-                    + ", allowedCommands=" + allowedCommands);
-        }
-        if (sessionBinder == null || allowedCommands == null) {
-            // Connection rejected.
-            close();
-            return;
-        }
-        synchronized (mLock) {
-            mSessionBinder = sessionBinder;
-            mAllowedCommands = allowedCommands;
-            mPlaybackActive = playbackActive;
-
-            // Implementation for the local binder is no-op,
-            // so can be used without worrying about deadlock.
-            sessionBinder.linkToDeath(mDeathRecipient, 0);
-            mConnectedToken = new Session2Token(mSessionToken.getUid(), TYPE_SESSION,
-                    mSessionToken.getPackageName(), sessionBinder, tokenExtras);
-        }
-        mCallbackExecutor.execute(() -> {
-            mCallback.onConnected(MediaController2.this, allowedCommands);
-        });
-    }
-
-    // Called by Controller2Link.onDisconnected
-    void onDisconnected(int seq) {
-        // close() will call mCallback.onDisconnected
-        close();
-    }
-
-    // Called by Controller2Link.onPlaybackActiveChanged
-    void onPlaybackActiveChanged(int seq, boolean playbackActive) {
-        synchronized (mLock) {
-            mPlaybackActive = playbackActive;
-        }
-        mCallbackExecutor.execute(() -> {
-            mCallback.onPlaybackActiveChanged(MediaController2.this, playbackActive);
-        });
-    }
-
-    // Called by Controller2Link.onSessionCommand
-    void onSessionCommand(int seq, Session2Command command, Bundle args,
-            @Nullable ResultReceiver resultReceiver) {
-        synchronized (mLock) {
-            mRequestedCommandSeqNumbers.add(seq);
-        }
-        mCallbackExecutor.execute(() -> {
-            boolean isCanceled;
-            synchronized (mLock) {
-                isCanceled = !mRequestedCommandSeqNumbers.remove(seq);
-            }
-            if (isCanceled) {
-                if (resultReceiver != null) {
-                    resultReceiver.send(RESULT_INFO_SKIPPED, null);
-                }
-                return;
-            }
-            Session2Command.Result result = mCallback.onSessionCommand(
-                    MediaController2.this, command, args);
-            if (resultReceiver != null) {
-                if (result == null) {
-                    resultReceiver.send(RESULT_INFO_SKIPPED, null);
-                } else {
-                    resultReceiver.send(result.getResultCode(), result.getResultData());
-                }
-            }
-        });
-    }
-
-    // Called by Controller2Link.onSessionCommand
-    void onCancelCommand(int seq) {
-        synchronized (mLock) {
-            mRequestedCommandSeqNumbers.remove(seq);
-        }
-    }
-
-    private int getNextSeqNumber() {
-        synchronized (mLock) {
-            return mNextSeqNumber++;
-        }
-    }
-
-    private Bundle createConnectionRequest(@NonNull Bundle connectionHints) {
-        Bundle connectionRequest = new Bundle();
-        connectionRequest.putString(KEY_PACKAGE_NAME, mContext.getPackageName());
-        connectionRequest.putInt(KEY_PID, Process.myPid());
-        connectionRequest.putBundle(KEY_CONNECTION_HINTS, connectionHints);
-        return connectionRequest;
-    }
-
-    private boolean requestConnectToSession(@NonNull Bundle connectionHints) {
-        Session2Link sessionBinder = mSessionToken.getSessionLink();
-        Bundle connectionRequest = createConnectionRequest(connectionHints);
-        try {
-            sessionBinder.connect(mControllerStub, getNextSeqNumber(), connectionRequest);
-        } catch (RuntimeException e) {
-            Log.w(TAG, "Failed to call connection request", e);
-            return false;
-        }
-        return true;
-    }
-
-    private boolean requestConnectToService() {
-        // Service. Needs to get fresh binder whenever connection is needed.
-        final Intent intent = new Intent(MediaSession2Service.SERVICE_INTERFACE);
-        intent.setClassName(mSessionToken.getPackageName(), mSessionToken.getServiceName());
-
-        // Use bindService() instead of startForegroundService() to start session service for three
-        // reasons.
-        // 1. Prevent session service owner's stopSelf() from destroying service.
-        //    With the startForegroundService(), service's call of stopSelf() will trigger immediate
-        //    onDestroy() calls on the main thread even when onConnect() is running in another
-        //    thread.
-        // 2. Minimize APIs for developers to take care about.
-        //    With bindService(), developers only need to take care about Service.onBind()
-        //    but Service.onStartCommand() should be also taken care about with the
-        //    startForegroundService().
-        // 3. Future support for UI-less playback
-        //    If a service wants to keep running, it should be either foreground service or
-        //    bound service. But there had been request for the feature for system apps
-        //    and using bindService() will be better fit with it.
-        synchronized (mLock) {
-            boolean result = mContext.bindService(
-                    intent, mServiceConnection, Context.BIND_AUTO_CREATE);
-            if (!result) {
-                Log.w(TAG, "bind to " + mSessionToken + " failed");
-                return false;
-            } else if (DEBUG) {
-                Log.d(TAG, "bind to " + mSessionToken + " succeeded");
-            }
-        }
-        return true;
-    }
-
-    /**
-     * This API is not generally intended for third party application developers.
-     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
-     * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
-     * Library</a> for consistent behavior across all devices.
-     * <p>
-     * Builder for {@link MediaController2}.
-     * <p>
-     * Any incoming event from the {@link MediaSession2} will be handled on the callback
-     * executor. If it's not set, {@link Context#getMainExecutor()} will be used by default.
-     */
-    public static final class Builder {
-        private Context mContext;
-        private Session2Token mToken;
-        private Bundle mConnectionHints;
-        private Executor mCallbackExecutor;
-        private ControllerCallback mCallback;
-
-        /**
-         * Creates a builder for {@link MediaController2}.
-         *
-         * @param context context
-         * @param token token of the session to connect to
-         */
-        public Builder(@NonNull Context context, @NonNull Session2Token token) {
-            if (context == null) {
-                throw new IllegalArgumentException("context shouldn't be null");
-            }
-            if (token == null) {
-                throw new IllegalArgumentException("token shouldn't be null");
-            }
-            mContext = context;
-            mToken = token;
-        }
-
-        /**
-         * Set the connection hints for the controller.
-         * <p>
-         * {@code connectionHints} is a session-specific argument to send to the session when
-         * connecting. The contents of this bundle may affect the connection result.
-         * <p>
-         * An {@link IllegalArgumentException} will be thrown if the bundle contains any
-         * non-framework Parcelable objects.
-         *
-         * @param connectionHints a bundle which contains the connection hints
-         * @return The Builder to allow chaining
-         */
-        @NonNull
-        public Builder setConnectionHints(@NonNull Bundle connectionHints) {
-            if (connectionHints == null) {
-                throw new IllegalArgumentException("connectionHints shouldn't be null");
-            }
-            if (MediaSession2.hasCustomParcelable(connectionHints)) {
-                throw new IllegalArgumentException("connectionHints shouldn't contain any custom "
-                        + "parcelables");
-            }
-            mConnectionHints = new Bundle(connectionHints);
-            return this;
-        }
-
-        /**
-         * Set callback for the controller and its executor.
-         *
-         * @param executor callback executor
-         * @param callback session callback.
-         * @return The Builder to allow chaining
-         */
-        @NonNull
-        public Builder setControllerCallback(@NonNull Executor executor,
-                @NonNull ControllerCallback 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;
-            return this;
-        }
-
-        /**
-         * Build {@link MediaController2}.
-         *
-         * @return a new controller
-         */
-        @NonNull
-        public MediaController2 build() {
-            if (mCallbackExecutor == null) {
-                mCallbackExecutor = mContext.getMainExecutor();
-            }
-            if (mCallback == null) {
-                mCallback = new ControllerCallback() {};
-            }
-            if (mConnectionHints == null) {
-                mConnectionHints = Bundle.EMPTY;
-            }
-            return new MediaController2(
-                    mContext, mToken, mConnectionHints, mCallbackExecutor, mCallback);
-        }
-    }
-
-    /**
-     * This API is not generally intended for third party application developers.
-     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
-     * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
-     * Library</a> for consistent behavior across all devices.
-     * <p>
-     * Interface for listening to change in activeness of the {@link MediaSession2}.
-     */
-    public abstract static class ControllerCallback {
-        /**
-         * Called when the controller is successfully connected to the session. The controller
-         * becomes available afterwards.
-         *
-         * @param controller the controller for this event
-         * @param allowedCommands commands that's allowed by the session.
-         */
-        public void onConnected(@NonNull MediaController2 controller,
-                @NonNull Session2CommandGroup allowedCommands) {}
-
-        /**
-         * Called when the session refuses the controller or the controller is disconnected from
-         * the session. The controller becomes unavailable afterwards and the callback wouldn't
-         * be called.
-         * <p>
-         * It will be also called after the {@link #close()}, so you can put clean up code here.
-         * You don't need to call {@link #close()} after this.
-         *
-         * @param controller the controller for this event
-         */
-        public void onDisconnected(@NonNull MediaController2 controller) {}
-
-        /**
-         * Called when the session's playback activeness is changed.
-         *
-         * @param controller the controller for this event
-         * @param playbackActive {@code true} if the session's playback is active.
-         *                       {@code false} otherwise.
-         * @see MediaController2#isPlaybackActive()
-         */
-        public void onPlaybackActiveChanged(@NonNull MediaController2 controller,
-                boolean playbackActive) {}
-
-        /**
-         * Called when the connected session sent a session command.
-         *
-         * @param controller the controller for this event
-         * @param command the session command
-         * @param args optional arguments
-         * @return the result for the session command. If {@code null}, RESULT_INFO_SKIPPED
-         *         will be sent to the session.
-         */
-        @Nullable
-        public Session2Command.Result onSessionCommand(@NonNull MediaController2 controller,
-                @NonNull Session2Command command, @Nullable Bundle args) {
-            return null;
-        }
-
-        /**
-         * Called when the command sent to the connected session is finished.
-         *
-         * @param controller the controller for this event
-         * @param token the token got from {@link MediaController2#sendSessionCommand}
-         * @param command the session command
-         * @param result the result of the session command
-         */
-        public void onCommandResult(@NonNull MediaController2 controller, @NonNull Object token,
-                @NonNull Session2Command command, @NonNull Session2Command.Result result) {}
-    }
-
-    // This will be called on the main thread.
-    private class SessionServiceConnection implements ServiceConnection {
-        private final Bundle mConnectionHints;
-
-        SessionServiceConnection(@Nullable Bundle connectionHints) {
-            mConnectionHints = connectionHints;
-        }
-
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            // Note that it's always main-thread.
-            boolean connectRequested = false;
-            try {
-                if (DEBUG) {
-                    Log.d(TAG, "onServiceConnected " + name + " " + this);
-                }
-                if (!mSessionToken.getPackageName().equals(name.getPackageName())) {
-                    Log.wtf(TAG, "Expected connection to " + mSessionToken.getPackageName()
-                            + " but is connected to " + name);
-                    return;
-                }
-                IMediaSession2Service iService = IMediaSession2Service.Stub.asInterface(service);
-                if (iService == null) {
-                    Log.wtf(TAG, "Service interface is missing.");
-                    return;
-                }
-                Bundle connectionRequest = createConnectionRequest(mConnectionHints);
-                iService.connect(mControllerStub, getNextSeqNumber(), connectionRequest);
-                connectRequested = true;
-            } catch (RemoteException e) {
-                Log.w(TAG, "Service " + name + " has died prematurely", e);
-            } finally {
-                if (!connectRequested) {
-                    close();
-                }
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            // Temporal lose of the binding because of the service crash. System will automatically
-            // rebind, so just no-op.
-            if (DEBUG) {
-                Log.w(TAG, "Session service " + name + " is disconnected.");
-            }
-            close();
-        }
-
-        @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.
-            close();
-        }
-    }
-}
diff --git a/apex/media/framework/java/android/media/MediaFeature.java b/apex/media/framework/java/android/media/MediaFeature.java
deleted file mode 100644
index 8d1b159..0000000
--- a/apex/media/framework/java/android/media/MediaFeature.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2020 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 android.media;
-
-import android.annotation.StringDef;
-import android.os.Build;
-
-import com.android.modules.annotation.MinSdk;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * MediaFeature defines various media features, e.g. hdr type.
- */
-@MinSdk(Build.VERSION_CODES.S)
-public final class MediaFeature {
-     /**
-     * Defines tye type of HDR(high dynamic range) video.
-     */
-    public static final class HdrType {
-        private HdrType() {
-        }
-
-        /**
-         * HDR type for dolby-vision.
-         */
-        public static final String DOLBY_VISION = "android.media.feature.hdr.dolby_vision";
-        /**
-         * HDR type for hdr10.
-         */
-        public static final String HDR10 = "android.media.feature.hdr.hdr10";
-        /**
-         * HDR type for hdr10+.
-         */
-        public static final String HDR10_PLUS = "android.media.feature.hdr.hdr10_plus";
-        /**
-         * HDR type for hlg.
-         */
-        public static final String HLG = "android.media.feature.hdr.hlg";
-    }
-
-    /** @hide */
-    @StringDef({
-            HdrType.DOLBY_VISION,
-            HdrType.HDR10,
-            HdrType.HDR10_PLUS,
-            HdrType.HLG,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface MediaHdrType {
-    }
-}
diff --git a/apex/media/framework/java/android/media/MediaFrameworkInitializer.java b/apex/media/framework/java/android/media/MediaFrameworkInitializer.java
deleted file mode 100644
index d7ad97d..0000000
--- a/apex/media/framework/java/android/media/MediaFrameworkInitializer.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2020 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 android.media;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.annotation.SystemApi.Client;
-import android.app.SystemServiceRegistry;
-import android.content.Context;
-import android.os.Build;
-
-import androidx.annotation.RequiresApi;
-
-import com.android.modules.annotation.MinSdk;
-import com.android.modules.utils.build.SdkLevel;
-
-/**
- * Class for performing registration for all media services on com.android.media apex.
- *
- * @hide
- */
-@MinSdk(Build.VERSION_CODES.S)
-@RequiresApi(Build.VERSION_CODES.S)
-@SystemApi(client = Client.MODULE_LIBRARIES)
-public class MediaFrameworkInitializer {
-    private MediaFrameworkInitializer() {
-    }
-
-    private static volatile MediaServiceManager sMediaServiceManager;
-
-    /**
-     * Sets an instance of {@link MediaServiceManager} that allows
-     * the media mainline module to register/obtain media binder services. This is called
-     * by the platform during the system initialization.
-     *
-     * @param mediaServiceManager instance of {@link MediaServiceManager} that allows
-     * the media mainline module to register/obtain media binder services.
-     */
-    public static void setMediaServiceManager(
-            @NonNull MediaServiceManager mediaServiceManager) {
-        if (sMediaServiceManager != null) {
-            throw new IllegalStateException("setMediaServiceManager called twice!");
-        }
-
-        if (mediaServiceManager == null) {
-            throw new NullPointerException("mediaServiceManager is null!");
-        }
-
-        sMediaServiceManager = mediaServiceManager;
-    }
-
-    /** @hide */
-    public static MediaServiceManager getMediaServiceManager() {
-        return sMediaServiceManager;
-    }
-
-    /**
-     * Called by {@link SystemServiceRegistry}'s static initializer and registers all media
-     * services to {@link Context}, so that {@link Context#getSystemService} can return them.
-     *
-     * @throws IllegalStateException if this is called from anywhere besides
-     * {@link SystemServiceRegistry}
-     */
-    public static void registerServiceWrappers() {
-        SystemServiceRegistry.registerContextAwareService(
-                Context.MEDIA_TRANSCODING_SERVICE,
-                MediaTranscodingManager.class,
-                context -> new MediaTranscodingManager(context)
-        );
-        if (SdkLevel.isAtLeastS()) {
-            SystemServiceRegistry.registerContextAwareService(
-                    Context.MEDIA_COMMUNICATION_SERVICE,
-                    MediaCommunicationManager.class,
-                    context -> new MediaCommunicationManager(context)
-            );
-        }
-    }
-}
diff --git a/apex/media/framework/java/android/media/MediaParceledListSlice.java b/apex/media/framework/java/android/media/MediaParceledListSlice.java
deleted file mode 100644
index fb36e80..0000000
--- a/apex/media/framework/java/android/media/MediaParceledListSlice.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2020 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 android.media;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import androidx.annotation.RequiresApi;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * This is a copied version of MediaParceledListSlice in framework with hidden API usages removed,
- * and also with some lint error fixed.
- *
- * Transfer a large list of Parcelable objects across an IPC.  Splits into
- * multiple transactions if needed.
- *
- * TODO: Remove this from @SystemApi once all the MediaSession related classes are moved
- *       to apex (or ParceledListSlice moved to apex). This class is temporaily added to system API
- *       for moving classes step by step.
- *
- * @param <T> The type of the elements in the list.
- * @see BaseMediaParceledListSlice
- * @deprecated This is temporary marked as @SystemApi. Should be removed from the API surface.
- * @hide
- */
-@Deprecated
-@RequiresApi(Build.VERSION_CODES.S)
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public final class MediaParceledListSlice<T extends Parcelable>
-        extends BaseMediaParceledListSlice<T> {
-    public MediaParceledListSlice(@NonNull List<T> list) {
-        super(list);
-    }
-
-    private MediaParceledListSlice(Parcel in, ClassLoader loader) {
-        super(in, loader);
-    }
-
-    @NonNull
-    public static <T extends Parcelable> MediaParceledListSlice<T> emptyList() {
-        return new MediaParceledListSlice<T>(Collections.<T> emptyList());
-    }
-
-    @Override
-    public int describeContents() {
-        int contents = 0;
-        final List<T> list = getList();
-        for (int i=0; i<list.size(); i++) {
-            contents |= list.get(i).describeContents();
-        }
-        return contents;
-    }
-
-    @Override
-    void writeElement(T parcelable, Parcel dest, int callFlags) {
-        parcelable.writeToParcel(dest, callFlags);
-    }
-
-    @Override
-    void writeParcelableCreator(T parcelable, Parcel dest) {
-        dest.writeParcelableCreator((Parcelable) parcelable);
-    }
-
-    @Override
-    Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader) {
-        return from.readParcelableCreator(loader);
-    }
-
-    @NonNull
-    @SuppressWarnings("unchecked")
-    public static final Parcelable.ClassLoaderCreator<MediaParceledListSlice> CREATOR =
-            new Parcelable.ClassLoaderCreator<MediaParceledListSlice>() {
-        public MediaParceledListSlice createFromParcel(Parcel in) {
-            return new MediaParceledListSlice(in, null);
-        }
-
-        @Override
-        public MediaParceledListSlice createFromParcel(Parcel in, ClassLoader loader) {
-            return new MediaParceledListSlice(in, loader);
-        }
-
-        @Override
-        public MediaParceledListSlice[] newArray(int size) {
-            return new MediaParceledListSlice[size];
-        }
-    };
-}
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
deleted file mode 100644
index b6f85c7..0000000
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ /dev/null
@@ -1,2293 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.media;
-
-import android.annotation.CheckResult;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringDef;
-import android.media.MediaCodec.CryptoInfo;
-import android.media.metrics.LogSessionId;
-import android.os.Build;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-import android.util.SparseArray;
-
-import androidx.annotation.RequiresApi;
-
-import com.android.modules.utils.build.SdkLevel;
-
-import com.google.android.exoplayer2.C;
-import com.google.android.exoplayer2.Format;
-import com.google.android.exoplayer2.ParserException;
-import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
-import com.google.android.exoplayer2.extractor.ChunkIndex;
-import com.google.android.exoplayer2.extractor.DefaultExtractorInput;
-import com.google.android.exoplayer2.extractor.Extractor;
-import com.google.android.exoplayer2.extractor.ExtractorInput;
-import com.google.android.exoplayer2.extractor.ExtractorOutput;
-import com.google.android.exoplayer2.extractor.PositionHolder;
-import com.google.android.exoplayer2.extractor.SeekMap.SeekPoints;
-import com.google.android.exoplayer2.extractor.TrackOutput;
-import com.google.android.exoplayer2.extractor.amr.AmrExtractor;
-import com.google.android.exoplayer2.extractor.flac.FlacExtractor;
-import com.google.android.exoplayer2.extractor.flv.FlvExtractor;
-import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
-import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor;
-import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor;
-import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor;
-import com.google.android.exoplayer2.extractor.ogg.OggExtractor;
-import com.google.android.exoplayer2.extractor.ts.Ac3Extractor;
-import com.google.android.exoplayer2.extractor.ts.Ac4Extractor;
-import com.google.android.exoplayer2.extractor.ts.AdtsExtractor;
-import com.google.android.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory;
-import com.google.android.exoplayer2.extractor.ts.PsExtractor;
-import com.google.android.exoplayer2.extractor.ts.TsExtractor;
-import com.google.android.exoplayer2.extractor.wav.WavExtractor;
-import com.google.android.exoplayer2.upstream.DataReader;
-import com.google.android.exoplayer2.util.ParsableByteArray;
-import com.google.android.exoplayer2.util.TimestampAdjuster;
-import com.google.android.exoplayer2.util.Util;
-import com.google.android.exoplayer2.video.ColorInfo;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.UUID;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.function.Function;
-
-/**
- * Parses media container formats and extracts contained media samples and metadata.
- *
- * <p>This class provides access to a battery of low-level media container parsers. Each instance of
- * this class is associated to a specific media parser implementation which is suitable for
- * extraction from a specific media container format. The media parser implementation assignment
- * depends on the factory method (see {@link #create} and {@link #createByName}) used to create the
- * instance.
- *
- * <p>Users must implement the following to use this class.
- *
- * <ul>
- *   <li>{@link InputReader}: Provides the media container's bytes to parse.
- *   <li>{@link OutputConsumer}: Provides a sink for all extracted data and metadata.
- * </ul>
- *
- * <p>The following code snippet includes a usage example:
- *
- * <pre>
- * MyOutputConsumer myOutputConsumer = new MyOutputConsumer();
- * MyInputReader myInputReader = new MyInputReader("www.example.com");
- * MediaParser mediaParser = MediaParser.create(myOutputConsumer);
- *
- * while (mediaParser.advance(myInputReader)) {}
- *
- * mediaParser.release();
- * mediaParser = null;
- * </pre>
- *
- * <p>The following code snippet provides a rudimentary {@link OutputConsumer} sample implementation
- * which extracts and publishes all video samples:
- *
- * <pre>
- * class VideoOutputConsumer implements MediaParser.OutputConsumer {
- *
- *     private byte[] sampleDataBuffer = new byte[4096];
- *     private byte[] discardedDataBuffer = new byte[4096];
- *     private int videoTrackIndex = -1;
- *     private int bytesWrittenCount = 0;
- *
- *     &#64;Override
- *     public void onSeekMapFound(int i, &#64;NonNull MediaFormat mediaFormat) {
- *       // Do nothing.
- *     }
- *
- *     &#64;Override
- *     public void onTrackDataFound(int i, &#64;NonNull TrackData trackData) {
- *       MediaFormat mediaFormat = trackData.mediaFormat;
- *       if (videoTrackIndex == -1 &amp;&amp;
- *           mediaFormat
- *               .getString(MediaFormat.KEY_MIME, &#47;* defaultValue= *&#47; "")
- *               .startsWith("video/")) {
- *         videoTrackIndex = i;
- *       }
- *     }
- *
- *     &#64;Override
- *     public void onSampleDataFound(int trackIndex, &#64;NonNull InputReader inputReader)
- *         throws IOException {
- *       int numberOfBytesToRead = (int) inputReader.getLength();
- *       if (videoTrackIndex != trackIndex) {
- *         // Discard contents.
- *         inputReader.read(
- *             discardedDataBuffer,
- *             &#47;* offset= *&#47; 0,
- *             Math.min(discardDataBuffer.length, numberOfBytesToRead));
- *       } else {
- *         ensureSpaceInBuffer(numberOfBytesToRead);
- *         int bytesRead = inputReader.read(
- *             sampleDataBuffer, bytesWrittenCount, numberOfBytesToRead);
- *         bytesWrittenCount += bytesRead;
- *       }
- *     }
- *
- *     &#64;Override
- *     public void onSampleCompleted(
- *         int trackIndex,
- *         long timeMicros,
- *         int flags,
- *         int size,
- *         int offset,
- *         &#64;Nullable CryptoInfo cryptoData) {
- *       if (videoTrackIndex != trackIndex) {
- *         return; // It's not the video track. Ignore.
- *       }
- *       byte[] sampleData = new byte[size];
- *       int sampleStartOffset = bytesWrittenCount - size - offset;
- *       System.arraycopy(
- *           sampleDataBuffer,
- *           sampleStartOffset,
- *           sampleData,
- *           &#47;* destPos= *&#47; 0,
- *           size);
- *       // Place trailing bytes at the start of the buffer.
- *       System.arraycopy(
- *           sampleDataBuffer,
- *           bytesWrittenCount - offset,
- *           sampleDataBuffer,
- *           &#47;* destPos= *&#47; 0,
- *           &#47;* size= *&#47; offset);
- *       bytesWrittenCount = bytesWrittenCount - offset;
- *       publishSample(sampleData, timeMicros, flags);
- *     }
- *
- *    private void ensureSpaceInBuffer(int numberOfBytesToRead) {
- *      int requiredLength = bytesWrittenCount + numberOfBytesToRead;
- *      if (requiredLength &gt; sampleDataBuffer.length) {
- *        sampleDataBuffer = Arrays.copyOf(sampleDataBuffer, requiredLength);
- *      }
- *    }
- *
- *   }
- *
- * </pre>
- */
-@RequiresApi(Build.VERSION_CODES.R)
-public final class MediaParser {
-
-    /**
-     * Maps seek positions to {@link SeekPoint SeekPoints} in the stream.
-     *
-     * <p>A {@link SeekPoint} is a position in the stream from which a player may successfully start
-     * playing media samples.
-     */
-    public static final class SeekMap {
-
-        /** Returned by {@link #getDurationMicros()} when the duration is unknown. */
-        public static final int UNKNOWN_DURATION = Integer.MIN_VALUE;
-
-        /**
-         * For each {@link #getSeekPoints} call, returns a single {@link SeekPoint} whose {@link
-         * SeekPoint#timeMicros} matches the requested timestamp, and whose {@link
-         * SeekPoint#position} is 0.
-         *
-         * @hide
-         */
-        public static final SeekMap DUMMY = new SeekMap(new DummyExoPlayerSeekMap());
-
-        private final com.google.android.exoplayer2.extractor.SeekMap mExoPlayerSeekMap;
-
-        private SeekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
-            mExoPlayerSeekMap = exoplayerSeekMap;
-        }
-
-        /** Returns whether seeking is supported. */
-        public boolean isSeekable() {
-            return mExoPlayerSeekMap.isSeekable();
-        }
-
-        /**
-         * Returns the duration of the stream in microseconds or {@link #UNKNOWN_DURATION} if the
-         * duration is unknown.
-         */
-        public long getDurationMicros() {
-            long durationUs = mExoPlayerSeekMap.getDurationUs();
-            return durationUs != C.TIME_UNSET ? durationUs : UNKNOWN_DURATION;
-        }
-
-        /**
-         * Obtains {@link SeekPoint SeekPoints} for the specified seek time in microseconds.
-         *
-         * <p>{@code getSeekPoints(timeMicros).first} contains the latest seek point for samples
-         * with timestamp equal to or smaller than {@code timeMicros}.
-         *
-         * <p>{@code getSeekPoints(timeMicros).second} contains the earliest seek point for samples
-         * with timestamp equal to or greater than {@code timeMicros}. If a seek point exists for
-         * {@code timeMicros}, the returned pair will contain the same {@link SeekPoint} twice.
-         *
-         * @param timeMicros A seek time in microseconds.
-         * @return The corresponding {@link SeekPoint SeekPoints}.
-         */
-        @NonNull
-        public Pair<SeekPoint, SeekPoint> getSeekPoints(long timeMicros) {
-            SeekPoints seekPoints = mExoPlayerSeekMap.getSeekPoints(timeMicros);
-            return new Pair<>(toSeekPoint(seekPoints.first), toSeekPoint(seekPoints.second));
-        }
-    }
-
-    /** Holds information associated with a track. */
-    public static final class TrackData {
-
-        /** Holds {@link MediaFormat} information for the track. */
-        @NonNull public final MediaFormat mediaFormat;
-
-        /**
-         * Holds {@link DrmInitData} necessary to acquire keys associated with the track, or null if
-         * the track has no encryption data.
-         */
-        @Nullable public final DrmInitData drmInitData;
-
-        private TrackData(MediaFormat mediaFormat, DrmInitData drmInitData) {
-            this.mediaFormat = mediaFormat;
-            this.drmInitData = drmInitData;
-        }
-    }
-
-    /** Defines a seek point in a media stream. */
-    public static final class SeekPoint {
-
-        /** A {@link SeekPoint} whose time and byte offset are both set to 0. */
-        @NonNull public static final SeekPoint START = new SeekPoint(0, 0);
-
-        /** The time of the seek point, in microseconds. */
-        public final long timeMicros;
-
-        /** The byte offset of the seek point. */
-        public final long position;
-
-        /**
-         * @param timeMicros The time of the seek point, in microseconds.
-         * @param position The byte offset of the seek point.
-         */
-        private SeekPoint(long timeMicros, long position) {
-            this.timeMicros = timeMicros;
-            this.position = position;
-        }
-
-        @Override
-        @NonNull
-        public String toString() {
-            return "[timeMicros=" + timeMicros + ", position=" + position + "]";
-        }
-
-        @Override
-        public boolean equals(@Nullable Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (obj == null || getClass() != obj.getClass()) {
-                return false;
-            }
-            SeekPoint other = (SeekPoint) obj;
-            return timeMicros == other.timeMicros && position == other.position;
-        }
-
-        @Override
-        public int hashCode() {
-            int result = (int) timeMicros;
-            result = 31 * result + (int) position;
-            return result;
-        }
-    }
-
-    /** Provides input data to {@link MediaParser}. */
-    public interface InputReader {
-
-        /**
-         * Reads up to {@code readLength} bytes of data and stores them into {@code buffer},
-         * starting at index {@code offset}.
-         *
-         * <p>This method blocks until at least one byte is read, the end of input is detected, or
-         * an exception is thrown. The read position advances to the first unread byte.
-         *
-         * @param buffer The buffer into which the read data should be stored.
-         * @param offset The start offset into {@code buffer} at which data should be written.
-         * @param readLength The maximum number of bytes to read.
-         * @return The non-zero number of bytes read, or -1 if no data is available because the end
-         *     of the input has been reached.
-         * @throws java.io.IOException If an error occurs reading from the source.
-         */
-        int read(@NonNull byte[] buffer, int offset, int readLength) throws IOException;
-
-        /** Returns the current read position (byte offset) in the stream. */
-        long getPosition();
-
-        /** Returns the length of the input in bytes, or -1 if the length is unknown. */
-        long getLength();
-    }
-
-    /** {@link InputReader} that allows setting the read position. */
-    public interface SeekableInputReader extends InputReader {
-
-        /**
-         * Sets the read position at the given {@code position}.
-         *
-         * <p>{@link #advance} will immediately return after calling this method.
-         *
-         * @param position The position to seek to, in bytes.
-         */
-        void seekToPosition(long position);
-    }
-
-    /** Receives extracted media sample data and metadata from {@link MediaParser}. */
-    public interface OutputConsumer {
-
-        /**
-         * Called when a {@link SeekMap} has been extracted from the stream.
-         *
-         * <p>This method is called at least once before any samples are {@link #onSampleCompleted
-         * complete}. May be called multiple times after that in order to add {@link SeekPoint
-         * SeekPoints}.
-         *
-         * @param seekMap The extracted {@link SeekMap}.
-         */
-        void onSeekMapFound(@NonNull SeekMap seekMap);
-
-        /**
-         * Called when the number of tracks is found.
-         *
-         * @param numberOfTracks The number of tracks in the stream.
-         */
-        void onTrackCountFound(int numberOfTracks);
-
-        /**
-         * Called when new {@link TrackData} is found in the stream.
-         *
-         * @param trackIndex The index of the track for which the {@link TrackData} was extracted.
-         * @param trackData The extracted {@link TrackData}.
-         */
-        void onTrackDataFound(int trackIndex, @NonNull TrackData trackData);
-
-        /**
-         * Called when sample data is found in the stream.
-         *
-         * <p>If the invocation of this method returns before the entire {@code inputReader} {@link
-         * InputReader#getLength() length} is consumed, the method will be called again for the
-         * implementer to read the remaining data. Implementers should surface any thrown {@link
-         * IOException} caused by reading from {@code input}.
-         *
-         * @param trackIndex The index of the track to which the sample data corresponds.
-         * @param inputReader The {@link InputReader} from which to read the data.
-         * @throws IOException If an exception occurs while reading from {@code inputReader}.
-         */
-        void onSampleDataFound(int trackIndex, @NonNull InputReader inputReader) throws IOException;
-
-        /**
-         * Called once all the data of a sample has been passed to {@link #onSampleDataFound}.
-         *
-         * <p>Includes sample metadata, like presentation timestamp and flags.
-         *
-         * @param trackIndex The index of the track to which the sample corresponds.
-         * @param timeMicros The media timestamp associated with the sample, in microseconds.
-         * @param flags Flags associated with the sample. See the {@code SAMPLE_FLAG_*} constants.
-         * @param size The size of the sample data, in bytes.
-         * @param offset The number of bytes that have been consumed by {@code
-         *     onSampleDataFound(int, MediaParser.InputReader)} for the specified track, since the
-         *     last byte belonging to the sample whose metadata is being passed.
-         * @param cryptoInfo Encryption data required to decrypt the sample. May be null for
-         *     unencrypted samples. Implementors should treat any output {@link CryptoInfo}
-         *     instances as immutable. MediaParser will not modify any output {@code cryptoInfos}
-         *     and implementors should not modify them either.
-         */
-        void onSampleCompleted(
-                int trackIndex,
-                long timeMicros,
-                @SampleFlags int flags,
-                int size,
-                int offset,
-                @Nullable CryptoInfo cryptoInfo);
-    }
-
-    /**
-     * Thrown if all parser implementations provided to {@link #create} failed to sniff the input
-     * content.
-     */
-    public static final class UnrecognizedInputFormatException extends IOException {
-
-        /**
-         * Creates a new instance which signals that the parsers with the given names failed to
-         * parse the input.
-         */
-        @NonNull
-        @CheckResult
-        private static UnrecognizedInputFormatException createForExtractors(
-                @NonNull String... extractorNames) {
-            StringBuilder builder = new StringBuilder();
-            builder.append("None of the available parsers ( ");
-            builder.append(extractorNames[0]);
-            for (int i = 1; i < extractorNames.length; i++) {
-                builder.append(", ");
-                builder.append(extractorNames[i]);
-            }
-            builder.append(") could read the stream.");
-            return new UnrecognizedInputFormatException(builder.toString());
-        }
-
-        private UnrecognizedInputFormatException(String extractorNames) {
-            super(extractorNames);
-        }
-    }
-
-    /** Thrown when an error occurs while parsing a media stream. */
-    public static final class ParsingException extends IOException {
-
-        private ParsingException(ParserException cause) {
-            super(cause);
-        }
-    }
-
-    // Sample flags.
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(
-            flag = true,
-            value = {
-                SAMPLE_FLAG_KEY_FRAME,
-                SAMPLE_FLAG_HAS_SUPPLEMENTAL_DATA,
-                SAMPLE_FLAG_LAST_SAMPLE,
-                SAMPLE_FLAG_ENCRYPTED,
-                SAMPLE_FLAG_DECODE_ONLY
-            })
-    public @interface SampleFlags {}
-    /** Indicates that the sample holds a synchronization sample. */
-    public static final int SAMPLE_FLAG_KEY_FRAME = MediaCodec.BUFFER_FLAG_KEY_FRAME;
-    /**
-     * Indicates that the sample has supplemental data.
-     *
-     * <p>Samples will not have this flag set unless the {@code
-     * "android.media.mediaparser.includeSupplementalData"} parameter is set to {@code true} via
-     * {@link #setParameter}.
-     *
-     * <p>Samples with supplemental data have the following sample data format:
-     *
-     * <ul>
-     *   <li>If the {@code "android.media.mediaparser.inBandCryptoInfo"} parameter is set, all
-     *       encryption information.
-     *   <li>(4 bytes) {@code sample_data_size}: The size of the actual sample data, not including
-     *       supplemental data or encryption information.
-     *   <li>({@code sample_data_size} bytes): The media sample data.
-     *   <li>(remaining bytes) The supplemental data.
-     * </ul>
-     */
-    public static final int SAMPLE_FLAG_HAS_SUPPLEMENTAL_DATA = 1 << 28;
-    /** Indicates that the sample is known to contain the last media sample of the stream. */
-    public static final int SAMPLE_FLAG_LAST_SAMPLE = 1 << 29;
-    /** Indicates that the sample is (at least partially) encrypted. */
-    public static final int SAMPLE_FLAG_ENCRYPTED = 1 << 30;
-    /** Indicates that the sample should be decoded but not rendered. */
-    public static final int SAMPLE_FLAG_DECODE_ONLY = 1 << 31;
-
-    // Parser implementation names.
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @StringDef(
-            prefix = {"PARSER_NAME_"},
-            value = {
-                PARSER_NAME_UNKNOWN,
-                PARSER_NAME_MATROSKA,
-                PARSER_NAME_FMP4,
-                PARSER_NAME_MP4,
-                PARSER_NAME_MP3,
-                PARSER_NAME_ADTS,
-                PARSER_NAME_AC3,
-                PARSER_NAME_TS,
-                PARSER_NAME_FLV,
-                PARSER_NAME_OGG,
-                PARSER_NAME_PS,
-                PARSER_NAME_WAV,
-                PARSER_NAME_AMR,
-                PARSER_NAME_AC4,
-                PARSER_NAME_FLAC
-            })
-    public @interface ParserName {}
-
-    /** Parser name returned by {@link #getParserName()} when no parser has been selected yet. */
-    public static final String PARSER_NAME_UNKNOWN = "android.media.mediaparser.UNKNOWN";
-    /**
-     * Parser for the Matroska container format, as defined in the <a
-     * href="https://matroska.org/technical/specs/">spec</a>.
-     */
-    public static final String PARSER_NAME_MATROSKA = "android.media.mediaparser.MatroskaParser";
-    /**
-     * Parser for fragmented files using the MP4 container format, as defined in ISO/IEC 14496-12.
-     */
-    public static final String PARSER_NAME_FMP4 = "android.media.mediaparser.FragmentedMp4Parser";
-    /**
-     * Parser for non-fragmented files using the MP4 container format, as defined in ISO/IEC
-     * 14496-12.
-     */
-    public static final String PARSER_NAME_MP4 = "android.media.mediaparser.Mp4Parser";
-    /** Parser for the MP3 container format, as defined in ISO/IEC 11172-3. */
-    public static final String PARSER_NAME_MP3 = "android.media.mediaparser.Mp3Parser";
-    /** Parser for the ADTS container format, as defined in ISO/IEC 13818-7. */
-    public static final String PARSER_NAME_ADTS = "android.media.mediaparser.AdtsParser";
-    /**
-     * Parser for the AC-3 container format, as defined in Digital Audio Compression Standard
-     * (AC-3).
-     */
-    public static final String PARSER_NAME_AC3 = "android.media.mediaparser.Ac3Parser";
-    /** Parser for the TS container format, as defined in ISO/IEC 13818-1. */
-    public static final String PARSER_NAME_TS = "android.media.mediaparser.TsParser";
-    /**
-     * Parser for the FLV container format, as defined in Adobe Flash Video File Format
-     * Specification.
-     */
-    public static final String PARSER_NAME_FLV = "android.media.mediaparser.FlvParser";
-    /** Parser for the OGG container format, as defined in RFC 3533. */
-    public static final String PARSER_NAME_OGG = "android.media.mediaparser.OggParser";
-    /** Parser for the PS container format, as defined in ISO/IEC 11172-1. */
-    public static final String PARSER_NAME_PS = "android.media.mediaparser.PsParser";
-    /**
-     * Parser for the WAV container format, as defined in Multimedia Programming Interface and Data
-     * Specifications.
-     */
-    public static final String PARSER_NAME_WAV = "android.media.mediaparser.WavParser";
-    /** Parser for the AMR container format, as defined in RFC 4867. */
-    public static final String PARSER_NAME_AMR = "android.media.mediaparser.AmrParser";
-    /**
-     * Parser for the AC-4 container format, as defined by Dolby AC-4: Audio delivery for
-     * Next-Generation Entertainment Services.
-     */
-    public static final String PARSER_NAME_AC4 = "android.media.mediaparser.Ac4Parser";
-    /**
-     * Parser for the FLAC container format, as defined in the <a
-     * href="https://xiph.org/flac/">spec</a>.
-     */
-    public static final String PARSER_NAME_FLAC = "android.media.mediaparser.FlacParser";
-
-    // MediaParser parameters.
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @StringDef(
-            prefix = {"PARAMETER_"},
-            value = {
-                PARAMETER_ADTS_ENABLE_CBR_SEEKING,
-                PARAMETER_AMR_ENABLE_CBR_SEEKING,
-                PARAMETER_FLAC_DISABLE_ID3,
-                PARAMETER_MP4_IGNORE_EDIT_LISTS,
-                PARAMETER_MP4_IGNORE_TFDT_BOX,
-                PARAMETER_MP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES,
-                PARAMETER_MATROSKA_DISABLE_CUES_SEEKING,
-                PARAMETER_MP3_DISABLE_ID3,
-                PARAMETER_MP3_ENABLE_CBR_SEEKING,
-                PARAMETER_MP3_ENABLE_INDEX_SEEKING,
-                PARAMETER_TS_MODE,
-                PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES,
-                PARAMETER_TS_IGNORE_AAC_STREAM,
-                PARAMETER_TS_IGNORE_AVC_STREAM,
-                PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM,
-                PARAMETER_TS_DETECT_ACCESS_UNITS,
-                PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS,
-                PARAMETER_IN_BAND_CRYPTO_INFO,
-                PARAMETER_INCLUDE_SUPPLEMENTAL_DATA
-            })
-    public @interface ParameterName {}
-
-    /**
-     * Sets whether constant bitrate seeking should be enabled for ADTS parsing. {@code boolean}
-     * expected. Default value is {@code false}.
-     */
-    public static final String PARAMETER_ADTS_ENABLE_CBR_SEEKING =
-            "android.media.mediaparser.adts.enableCbrSeeking";
-    /**
-     * Sets whether constant bitrate seeking should be enabled for AMR. {@code boolean} expected.
-     * Default value is {@code false}.
-     */
-    public static final String PARAMETER_AMR_ENABLE_CBR_SEEKING =
-            "android.media.mediaparser.amr.enableCbrSeeking";
-    /**
-     * Sets whether the ID3 track should be disabled for FLAC. {@code boolean} expected. Default
-     * value is {@code false}.
-     */
-    public static final String PARAMETER_FLAC_DISABLE_ID3 =
-            "android.media.mediaparser.flac.disableId3";
-    /**
-     * Sets whether MP4 parsing should ignore edit lists. {@code boolean} expected. Default value is
-     * {@code false}.
-     */
-    public static final String PARAMETER_MP4_IGNORE_EDIT_LISTS =
-            "android.media.mediaparser.mp4.ignoreEditLists";
-    /**
-     * Sets whether MP4 parsing should ignore the tfdt box. {@code boolean} expected. Default value
-     * is {@code false}.
-     */
-    public static final String PARAMETER_MP4_IGNORE_TFDT_BOX =
-            "android.media.mediaparser.mp4.ignoreTfdtBox";
-    /**
-     * Sets whether MP4 parsing should treat all video frames as key frames. {@code boolean}
-     * expected. Default value is {@code false}.
-     */
-    public static final String PARAMETER_MP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES =
-            "android.media.mediaparser.mp4.treatVideoFramesAsKeyframes";
-    /**
-     * Sets whether Matroska parsing should avoid seeking to the cues element. {@code boolean}
-     * expected. Default value is {@code false}.
-     *
-     * <p>If this flag is enabled and the cues element occurs after the first cluster, then the
-     * media is treated as unseekable.
-     */
-    public static final String PARAMETER_MATROSKA_DISABLE_CUES_SEEKING =
-            "android.media.mediaparser.matroska.disableCuesSeeking";
-    /**
-     * Sets whether the ID3 track should be disabled for MP3. {@code boolean} expected. Default
-     * value is {@code false}.
-     */
-    public static final String PARAMETER_MP3_DISABLE_ID3 =
-            "android.media.mediaparser.mp3.disableId3";
-    /**
-     * Sets whether constant bitrate seeking should be enabled for MP3. {@code boolean} expected.
-     * Default value is {@code false}.
-     */
-    public static final String PARAMETER_MP3_ENABLE_CBR_SEEKING =
-            "android.media.mediaparser.mp3.enableCbrSeeking";
-    /**
-     * Sets whether MP3 parsing should generate a time-to-byte mapping. {@code boolean} expected.
-     * Default value is {@code false}.
-     *
-     * <p>Enabling this flag may require to scan a significant portion of the file to compute a seek
-     * point. Therefore, it should only be used if:
-     *
-     * <ul>
-     *   <li>the file is small, or
-     *   <li>the bitrate is variable (or the type of bitrate is unknown) and the seeking metadata
-     *       provided in the file is not precise enough (or is not present).
-     * </ul>
-     */
-    public static final String PARAMETER_MP3_ENABLE_INDEX_SEEKING =
-            "android.media.mediaparser.mp3.enableIndexSeeking";
-    /**
-     * Sets the operation mode for TS parsing. {@code String} expected. Valid values are {@code
-     * "single_pmt"}, {@code "multi_pmt"}, and {@code "hls"}. Default value is {@code "single_pmt"}.
-     *
-     * <p>The operation modes alter the way TS behaves so that it can handle certain kinds of
-     * commonly-occurring malformed media.
-     *
-     * <ul>
-     *   <li>{@code "single_pmt"}: Only the first found PMT is parsed. Others are ignored, even if
-     *       more PMTs are declared in the PAT.
-     *   <li>{@code "multi_pmt"}: Behave as described in ISO/IEC 13818-1.
-     *   <li>{@code "hls"}: Enable {@code "single_pmt"} mode, and ignore continuity counters.
-     * </ul>
-     */
-    public static final String PARAMETER_TS_MODE = "android.media.mediaparser.ts.mode";
-    /**
-     * Sets whether TS should treat samples consisting of non-IDR I slices as synchronization
-     * samples (key-frames). {@code boolean} expected. Default value is {@code false}.
-     */
-    public static final String PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES =
-            "android.media.mediaparser.ts.allowNonIdrAvcKeyframes";
-    /**
-     * Sets whether TS parsing should ignore AAC elementary streams. {@code boolean} expected.
-     * Default value is {@code false}.
-     */
-    public static final String PARAMETER_TS_IGNORE_AAC_STREAM =
-            "android.media.mediaparser.ts.ignoreAacStream";
-    /**
-     * Sets whether TS parsing should ignore AVC elementary streams. {@code boolean} expected.
-     * Default value is {@code false}.
-     */
-    public static final String PARAMETER_TS_IGNORE_AVC_STREAM =
-            "android.media.mediaparser.ts.ignoreAvcStream";
-    /**
-     * Sets whether TS parsing should ignore splice information streams. {@code boolean} expected.
-     * Default value is {@code false}.
-     */
-    public static final String PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM =
-            "android.media.mediaparser.ts.ignoreSpliceInfoStream";
-    /**
-     * Sets whether TS parsing should split AVC stream into access units based on slice headers.
-     * {@code boolean} expected. Default value is {@code false}.
-     *
-     * <p>This flag should be left disabled if the stream contains access units delimiters in order
-     * to avoid unnecessary computational costs.
-     */
-    public static final String PARAMETER_TS_DETECT_ACCESS_UNITS =
-            "android.media.mediaparser.ts.ignoreDetectAccessUnits";
-    /**
-     * Sets whether TS parsing should handle HDMV DTS audio streams. {@code boolean} expected.
-     * Default value is {@code false}.
-     *
-     * <p>Enabling this flag will disable the detection of SCTE subtitles.
-     */
-    public static final String PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS =
-            "android.media.mediaparser.ts.enableHdmvDtsAudioStreams";
-    /**
-     * Sets whether encryption data should be sent in-band with the sample data, as per {@link
-     * OutputConsumer#onSampleDataFound}. {@code boolean} expected. Default value is {@code false}.
-     *
-     * <p>If this parameter is set, encrypted samples' data will be prefixed with the encryption
-     * information bytes. The format for in-band encryption information is:
-     *
-     * <ul>
-     *   <li>(1 byte) {@code encryption_signal_byte}: Most significant bit signals whether the
-     *       encryption data contains subsample encryption data. The remaining bits contain {@code
-     *       initialization_vector_size}.
-     *   <li>({@code initialization_vector_size} bytes) Initialization vector.
-     *   <li>If subsample encryption data is present, as per {@code encryption_signal_byte}, the
-     *       encryption data also contains:
-     *       <ul>
-     *         <li>(2 bytes) {@code subsample_encryption_data_length}.
-     *         <li>({@code subsample_encryption_data_length * 6} bytes) Subsample encryption data
-     *             (repeated {@code subsample_encryption_data_length} times):
-     *             <ul>
-     *               <li>(2 bytes) Size of a clear section in sample.
-     *               <li>(4 bytes) Size of an encryption section in sample.
-     *             </ul>
-     *       </ul>
-     * </ul>
-     *
-     * @hide
-     */
-    public static final String PARAMETER_IN_BAND_CRYPTO_INFO =
-            "android.media.mediaparser.inBandCryptoInfo";
-    /**
-     * Sets whether supplemental data should be included as part of the sample data. {@code boolean}
-     * expected. Default value is {@code false}. See {@link #SAMPLE_FLAG_HAS_SUPPLEMENTAL_DATA} for
-     * information about the sample data format.
-     *
-     * @hide
-     */
-    public static final String PARAMETER_INCLUDE_SUPPLEMENTAL_DATA =
-            "android.media.mediaparser.includeSupplementalData";
-    /**
-     * Sets whether sample timestamps may start from non-zero offsets. {@code boolean} expected.
-     * Default value is {@code false}.
-     *
-     * <p>When set to true, sample timestamps will not be offset to start from zero, and the media
-     * provided timestamps will be used instead. For example, transport stream sample timestamps
-     * will not be converted to a zero-based timebase.
-     *
-     * @hide
-     */
-    public static final String PARAMETER_IGNORE_TIMESTAMP_OFFSET =
-            "android.media.mediaparser.ignoreTimestampOffset";
-    /**
-     * Sets whether each track type should be eagerly exposed. {@code boolean} expected. Default
-     * value is {@code false}.
-     *
-     * <p>When set to true, each track type will be eagerly exposed through a call to {@link
-     * OutputConsumer#onTrackDataFound} containing a single-value {@link MediaFormat}. The key for
-     * the track type is {@code "track-type-string"}, and the possible values are {@code "video"},
-     * {@code "audio"}, {@code "text"}, {@code "metadata"}, and {@code "unknown"}.
-     *
-     * @hide
-     */
-    public static final String PARAMETER_EAGERLY_EXPOSE_TRACKTYPE =
-            "android.media.mediaparser.eagerlyExposeTrackType";
-    /**
-     * Sets whether a dummy {@link SeekMap} should be exposed before starting extraction. {@code
-     * boolean} expected. Default value is {@code false}.
-     *
-     * <p>For each {@link SeekMap#getSeekPoints} call, the dummy {@link SeekMap} returns a single
-     * {@link SeekPoint} whose {@link SeekPoint#timeMicros} matches the requested timestamp, and
-     * whose {@link SeekPoint#position} is 0.
-     *
-     * @hide
-     */
-    public static final String PARAMETER_EXPOSE_DUMMY_SEEKMAP =
-            "android.media.mediaparser.exposeDummySeekMap";
-
-    /**
-     * Sets whether chunk indices available in the extracted media should be exposed as {@link
-     * MediaFormat MediaFormats}. {@code boolean} expected. Default value is {@link false}.
-     *
-     * <p>When set to true, any information about media segmentation will be exposed as a {@link
-     * MediaFormat} (with track index 0) containing four {@link ByteBuffer} elements under the
-     * following keys:
-     *
-     * <ul>
-     *   <li>"chunk-index-int-sizes": Contains {@code ints} representing the sizes in bytes of each
-     *       of the media segments.
-     *   <li>"chunk-index-long-offsets": Contains {@code longs} representing the byte offsets of
-     *       each segment in the stream.
-     *   <li>"chunk-index-long-us-durations": Contains {@code longs} representing the media duration
-     *       of each segment, in microseconds.
-     *   <li>"chunk-index-long-us-times": Contains {@code longs} representing the start time of each
-     *       segment, in microseconds.
-     * </ul>
-     *
-     * @hide
-     */
-    public static final String PARAMETER_EXPOSE_CHUNK_INDEX_AS_MEDIA_FORMAT =
-            "android.media.mediaParser.exposeChunkIndexAsMediaFormat";
-    /**
-     * Sets a list of closed-caption {@link MediaFormat MediaFormats} that should be exposed as part
-     * of the extracted media. {@code List<MediaFormat>} expected. Default value is an empty list.
-     *
-     * <p>Expected keys in the {@link MediaFormat} are:
-     *
-     * <ul>
-     *   <p>{@link MediaFormat#KEY_MIME}: Determine the type of captions (for example,
-     *   application/cea-608). Mandatory.
-     *   <p>{@link MediaFormat#KEY_CAPTION_SERVICE_NUMBER}: Determine the channel on which the
-     *   captions are transmitted. Optional.
-     * </ul>
-     *
-     * @hide
-     */
-    public static final String PARAMETER_EXPOSE_CAPTION_FORMATS =
-            "android.media.mediaParser.exposeCaptionFormats";
-    /**
-     * Sets whether the value associated with {@link #PARAMETER_EXPOSE_CAPTION_FORMATS} should
-     * override any in-band caption service declarations. {@code boolean} expected. Default value is
-     * {@link false}.
-     *
-     * <p>When {@code false}, any present in-band caption services information will override the
-     * values associated with {@link #PARAMETER_EXPOSE_CAPTION_FORMATS}.
-     *
-     * @hide
-     */
-    public static final String PARAMETER_OVERRIDE_IN_BAND_CAPTION_DECLARATIONS =
-            "android.media.mediaParser.overrideInBandCaptionDeclarations";
-    /**
-     * Sets whether a track for EMSG events should be exposed in case of parsing a container that
-     * supports them. {@code boolean} expected. Default value is {@link false}.
-     *
-     * @hide
-     */
-    public static final String PARAMETER_EXPOSE_EMSG_TRACK =
-            "android.media.mediaParser.exposeEmsgTrack";
-
-    // Private constants.
-
-    private static final String TAG = "MediaParser";
-    private static final String JNI_LIBRARY_NAME = "mediaparser-jni";
-    private static final Map<String, ExtractorFactory> EXTRACTOR_FACTORIES_BY_NAME;
-    private static final Map<String, Class> EXPECTED_TYPE_BY_PARAMETER_NAME;
-    private static final String TS_MODE_SINGLE_PMT = "single_pmt";
-    private static final String TS_MODE_MULTI_PMT = "multi_pmt";
-    private static final String TS_MODE_HLS = "hls";
-    private static final int BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY = 6;
-    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
-    private static final String MEDIAMETRICS_ELEMENT_SEPARATOR = "|";
-    private static final int MEDIAMETRICS_MAX_STRING_SIZE = 200;
-    private static final int MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH;
-    /**
-     * Intentional error introduced to reported metrics to prevent identification of the parsed
-     * media. Note: Increasing this value may cause older hostside CTS tests to fail.
-     */
-    private static final float MEDIAMETRICS_DITHER = .02f;
-
-    @IntDef(
-            value = {
-                STATE_READING_SIGNAL_BYTE,
-                STATE_READING_INIT_VECTOR,
-                STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE,
-                STATE_READING_SUBSAMPLE_ENCRYPTION_DATA
-            })
-    private @interface EncryptionDataReadState {}
-
-    private static final int STATE_READING_SIGNAL_BYTE = 0;
-    private static final int STATE_READING_INIT_VECTOR = 1;
-    private static final int STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE = 2;
-    private static final int STATE_READING_SUBSAMPLE_ENCRYPTION_DATA = 3;
-
-    // Instance creation methods.
-
-    /**
-     * Creates an instance backed by the parser with the given {@code name}. The returned instance
-     * will attempt parsing without sniffing the content.
-     *
-     * @param name The name of the parser that will be associated with the created instance.
-     * @param outputConsumer The {@link OutputConsumer} to which track data and samples are pushed.
-     * @return A new instance.
-     * @throws IllegalArgumentException If an invalid name is provided.
-     */
-    @NonNull
-    public static MediaParser createByName(
-            @NonNull @ParserName String name, @NonNull OutputConsumer outputConsumer) {
-        String[] nameAsArray = new String[] {name};
-        assertValidNames(nameAsArray);
-        return new MediaParser(outputConsumer, /* createdByName= */ true, name);
-    }
-
-    /**
-     * Creates an instance whose backing parser will be selected by sniffing the content during the
-     * first {@link #advance} call. Parser implementations will sniff the content in order of
-     * appearance in {@code parserNames}.
-     *
-     * @param outputConsumer The {@link OutputConsumer} to which extracted data is output.
-     * @param parserNames The names of the parsers to sniff the content with. If empty, a default
-     *     array of names is used.
-     * @return A new instance.
-     */
-    @NonNull
-    public static MediaParser create(
-            @NonNull OutputConsumer outputConsumer, @NonNull @ParserName String... parserNames) {
-        assertValidNames(parserNames);
-        if (parserNames.length == 0) {
-            parserNames = EXTRACTOR_FACTORIES_BY_NAME.keySet().toArray(new String[0]);
-        }
-        return new MediaParser(outputConsumer, /* createdByName= */ false, parserNames);
-    }
-
-    // Misc static methods.
-
-    /**
-     * Returns an immutable list with the names of the parsers that are suitable for container
-     * formats with the given {@link MediaFormat}.
-     *
-     * <p>A parser supports a {@link MediaFormat} if the mime type associated with {@link
-     * MediaFormat#KEY_MIME} corresponds to the supported container format.
-     *
-     * @param mediaFormat The {@link MediaFormat} to check support for.
-     * @return The parser names that support the given {@code mediaFormat}, or the list of all
-     *     parsers available if no container specific format information is provided.
-     */
-    @NonNull
-    @ParserName
-    public static List<String> getParserNames(@NonNull MediaFormat mediaFormat) {
-        String mimeType = mediaFormat.getString(MediaFormat.KEY_MIME);
-        mimeType = mimeType == null ? null : Util.toLowerInvariant(mimeType.trim());
-        if (TextUtils.isEmpty(mimeType)) {
-            // No MIME type provided. Return all.
-            return Collections.unmodifiableList(
-                    new ArrayList<>(EXTRACTOR_FACTORIES_BY_NAME.keySet()));
-        }
-        ArrayList<String> result = new ArrayList<>();
-        switch (mimeType) {
-            case "video/x-matroska":
-            case "audio/x-matroska":
-            case "video/x-webm":
-            case "audio/x-webm":
-                result.add(PARSER_NAME_MATROSKA);
-                break;
-            case "video/mp4":
-            case "audio/mp4":
-            case "application/mp4":
-                result.add(PARSER_NAME_MP4);
-                result.add(PARSER_NAME_FMP4);
-                break;
-            case "audio/mpeg":
-                result.add(PARSER_NAME_MP3);
-                break;
-            case "audio/aac":
-                result.add(PARSER_NAME_ADTS);
-                break;
-            case "audio/ac3":
-                result.add(PARSER_NAME_AC3);
-                break;
-            case "video/mp2t":
-            case "audio/mp2t":
-                result.add(PARSER_NAME_TS);
-                break;
-            case "video/x-flv":
-                result.add(PARSER_NAME_FLV);
-                break;
-            case "video/ogg":
-            case "audio/ogg":
-            case "application/ogg":
-                result.add(PARSER_NAME_OGG);
-                break;
-            case "video/mp2p":
-            case "video/mp1s":
-                result.add(PARSER_NAME_PS);
-                break;
-            case "audio/vnd.wave":
-            case "audio/wav":
-            case "audio/wave":
-            case "audio/x-wav":
-                result.add(PARSER_NAME_WAV);
-                break;
-            case "audio/amr":
-                result.add(PARSER_NAME_AMR);
-                break;
-            case "audio/ac4":
-                result.add(PARSER_NAME_AC4);
-                break;
-            case "audio/flac":
-            case "audio/x-flac":
-                result.add(PARSER_NAME_FLAC);
-                break;
-            default:
-                // No parsers support the given mime type. Do nothing.
-                break;
-        }
-        return Collections.unmodifiableList(result);
-    }
-
-    // Private fields.
-
-    private final Map<String, Object> mParserParameters;
-    private final OutputConsumer mOutputConsumer;
-    private final String[] mParserNamesPool;
-    private final PositionHolder mPositionHolder;
-    private final InputReadingDataReader mExoDataReader;
-    private final DataReaderAdapter mScratchDataReaderAdapter;
-    private final ParsableByteArrayAdapter mScratchParsableByteArrayAdapter;
-    @Nullable private final Constructor<DrmInitData.SchemeInitData> mSchemeInitDataConstructor;
-    private final ArrayList<Format> mMuxedCaptionFormats;
-    private boolean mInBandCryptoInfo;
-    private boolean mIncludeSupplementalData;
-    private boolean mIgnoreTimestampOffset;
-    private boolean mEagerlyExposeTrackType;
-    private boolean mExposeDummySeekMap;
-    private boolean mExposeChunkIndexAsMediaFormat;
-    private String mParserName;
-    private Extractor mExtractor;
-    private ExtractorInput mExtractorInput;
-    private boolean mPendingExtractorInit;
-    private long mPendingSeekPosition;
-    private long mPendingSeekTimeMicros;
-    private boolean mLoggedSchemeInitDataCreationException;
-    private boolean mReleased;
-
-    // MediaMetrics fields.
-    @Nullable private LogSessionId mLogSessionId;
-    private final boolean mCreatedByName;
-    private final SparseArray<Format> mTrackFormats;
-    private String mLastObservedExceptionName;
-    private long mDurationMillis;
-    private long mResourceByteCount;
-
-    // Public methods.
-
-    /**
-     * Sets parser-specific parameters which allow customizing behavior.
-     *
-     * <p>Must be called before the first call to {@link #advance}.
-     *
-     * @param parameterName The name of the parameter to set. See {@code PARAMETER_*} constants for
-     *     documentation on possible values.
-     * @param value The value to set for the given {@code parameterName}. See {@code PARAMETER_*}
-     *     constants for documentation on the expected types.
-     * @return This instance, for convenience.
-     * @throws IllegalStateException If called after calling {@link #advance} on the same instance.
-     */
-    @NonNull
-    public MediaParser setParameter(
-            @NonNull @ParameterName String parameterName, @NonNull Object value) {
-        if (mExtractor != null) {
-            throw new IllegalStateException(
-                    "setParameters() must be called before the first advance() call.");
-        }
-        Class expectedType = EXPECTED_TYPE_BY_PARAMETER_NAME.get(parameterName);
-        // Ignore parameter names that are not contained in the map, in case the client is passing
-        // a parameter that is being added in a future version of this library.
-        if (expectedType != null && !expectedType.isInstance(value)) {
-            throw new IllegalArgumentException(
-                    parameterName
-                            + " expects a "
-                            + expectedType.getSimpleName()
-                            + " but a "
-                            + value.getClass().getSimpleName()
-                            + " was passed.");
-        }
-        if (PARAMETER_TS_MODE.equals(parameterName)
-                && !TS_MODE_SINGLE_PMT.equals(value)
-                && !TS_MODE_HLS.equals(value)
-                && !TS_MODE_MULTI_PMT.equals(value)) {
-            throw new IllegalArgumentException(PARAMETER_TS_MODE + " does not accept: " + value);
-        }
-        if (PARAMETER_IN_BAND_CRYPTO_INFO.equals(parameterName)) {
-            mInBandCryptoInfo = (boolean) value;
-        }
-        if (PARAMETER_INCLUDE_SUPPLEMENTAL_DATA.equals(parameterName)) {
-            mIncludeSupplementalData = (boolean) value;
-        }
-        if (PARAMETER_IGNORE_TIMESTAMP_OFFSET.equals(parameterName)) {
-            mIgnoreTimestampOffset = (boolean) value;
-        }
-        if (PARAMETER_EAGERLY_EXPOSE_TRACKTYPE.equals(parameterName)) {
-            mEagerlyExposeTrackType = (boolean) value;
-        }
-        if (PARAMETER_EXPOSE_DUMMY_SEEKMAP.equals(parameterName)) {
-            mExposeDummySeekMap = (boolean) value;
-        }
-        if (PARAMETER_EXPOSE_CHUNK_INDEX_AS_MEDIA_FORMAT.equals(parameterName)) {
-            mExposeChunkIndexAsMediaFormat = (boolean) value;
-        }
-        if (PARAMETER_EXPOSE_CAPTION_FORMATS.equals(parameterName)) {
-            setMuxedCaptionFormats((List<MediaFormat>) value);
-        }
-        mParserParameters.put(parameterName, value);
-        return this;
-    }
-
-    /**
-     * Returns whether the given {@code parameterName} is supported by this parser.
-     *
-     * @param parameterName The parameter name to check support for. One of the {@code PARAMETER_*}
-     *     constants.
-     * @return Whether the given {@code parameterName} is supported.
-     */
-    public boolean supportsParameter(@NonNull @ParameterName String parameterName) {
-        return EXPECTED_TYPE_BY_PARAMETER_NAME.containsKey(parameterName);
-    }
-
-    /**
-     * Returns the name of the backing parser implementation.
-     *
-     * <p>If this instance was creating using {@link #createByName}, the provided name is returned.
-     * If this instance was created using {@link #create}, this method will return {@link
-     * #PARSER_NAME_UNKNOWN} until the first call to {@link #advance}, after which the name of the
-     * backing parser implementation is returned.
-     *
-     * @return The name of the backing parser implementation, or null if the backing parser
-     *     implementation has not yet been selected.
-     */
-    @NonNull
-    @ParserName
-    public String getParserName() {
-        return mParserName;
-    }
-
-    /**
-     * Makes progress in the extraction of the input media stream, unless the end of the input has
-     * been reached.
-     *
-     * <p>This method will block until some progress has been made.
-     *
-     * <p>If this instance was created using {@link #create}, the first call to this method will
-     * sniff the content using the selected parser implementations.
-     *
-     * @param seekableInputReader The {@link SeekableInputReader} from which to obtain the media
-     *     container data.
-     * @return Whether there is any data left to extract. Returns false if the end of input has been
-     *     reached.
-     * @throws IOException If an error occurs while reading from the {@link SeekableInputReader}.
-     * @throws UnrecognizedInputFormatException If the format cannot be recognized by any of the
-     *     underlying parser implementations.
-     */
-    public boolean advance(@NonNull SeekableInputReader seekableInputReader) throws IOException {
-        if (mExtractorInput == null) {
-            // TODO: For efficiency, the same implementation should be used, by providing a
-            // clearBuffers() method, or similar.
-            long resourceLength = seekableInputReader.getLength();
-            if (mResourceByteCount == 0) {
-                // For resource byte count metric collection, we only take into account the length
-                // of the first provided input reader.
-                mResourceByteCount = resourceLength;
-            }
-            mExtractorInput =
-                    new DefaultExtractorInput(
-                            mExoDataReader, seekableInputReader.getPosition(), resourceLength);
-        }
-        mExoDataReader.mInputReader = seekableInputReader;
-
-        if (mExtractor == null) {
-            mPendingExtractorInit = true;
-            if (!mParserName.equals(PARSER_NAME_UNKNOWN)) {
-                mExtractor = createExtractor(mParserName);
-            } else {
-                for (String parserName : mParserNamesPool) {
-                    Extractor extractor = createExtractor(parserName);
-                    try {
-                        if (extractor.sniff(mExtractorInput)) {
-                            mParserName = parserName;
-                            mExtractor = extractor;
-                            mPendingExtractorInit = true;
-                            break;
-                        }
-                    } catch (EOFException e) {
-                        // Do nothing.
-                    } finally {
-                        mExtractorInput.resetPeekPosition();
-                    }
-                }
-                if (mExtractor == null) {
-                    UnrecognizedInputFormatException exception =
-                            UnrecognizedInputFormatException.createForExtractors(mParserNamesPool);
-                    mLastObservedExceptionName = exception.getClass().getName();
-                    throw exception;
-                }
-                return true;
-            }
-        }
-
-        if (mPendingExtractorInit) {
-            if (mExposeDummySeekMap) {
-                // We propagate the dummy seek map before initializing the extractor, in case the
-                // extractor initialization outputs a seek map.
-                mOutputConsumer.onSeekMapFound(SeekMap.DUMMY);
-            }
-            mExtractor.init(new ExtractorOutputAdapter());
-            mPendingExtractorInit = false;
-            // We return after initialization to allow clients use any output information before
-            // starting actual extraction.
-            return true;
-        }
-
-        if (isPendingSeek()) {
-            mExtractor.seek(mPendingSeekPosition, mPendingSeekTimeMicros);
-            removePendingSeek();
-        }
-
-        mPositionHolder.position = seekableInputReader.getPosition();
-        int result;
-        try {
-            result = mExtractor.read(mExtractorInput, mPositionHolder);
-        } catch (Exception e) {
-            mLastObservedExceptionName = e.getClass().getName();
-            if (e instanceof ParserException) {
-                throw new ParsingException((ParserException) e);
-            } else {
-                throw e;
-            }
-        }
-        if (result == Extractor.RESULT_END_OF_INPUT) {
-            mExtractorInput = null;
-            return false;
-        }
-        if (result == Extractor.RESULT_SEEK) {
-            mExtractorInput = null;
-            seekableInputReader.seekToPosition(mPositionHolder.position);
-        }
-        return true;
-    }
-
-    /**
-     * Seeks within the media container being extracted.
-     *
-     * <p>{@link SeekPoint SeekPoints} can be obtained from the {@link SeekMap} passed to {@link
-     * OutputConsumer#onSeekMapFound(SeekMap)}.
-     *
-     * <p>Following a call to this method, the {@link InputReader} passed to the next invocation of
-     * {@link #advance} must provide data starting from {@link SeekPoint#position} in the stream.
-     *
-     * @param seekPoint The {@link SeekPoint} to seek to.
-     */
-    public void seek(@NonNull SeekPoint seekPoint) {
-        if (mExtractor == null) {
-            mPendingSeekPosition = seekPoint.position;
-            mPendingSeekTimeMicros = seekPoint.timeMicros;
-        } else {
-            mExtractor.seek(seekPoint.position, seekPoint.timeMicros);
-        }
-    }
-
-    /**
-     * Releases any acquired resources.
-     *
-     * <p>After calling this method, this instance becomes unusable and no other methods should be
-     * invoked.
-     */
-    public void release() {
-        mExtractorInput = null;
-        mExtractor = null;
-        if (mReleased) {
-            // Nothing to do.
-            return;
-        }
-        mReleased = true;
-
-        String trackMimeTypes = buildMediaMetricsString(format -> format.sampleMimeType);
-        String trackCodecs = buildMediaMetricsString(format -> format.codecs);
-        int videoWidth = -1;
-        int videoHeight = -1;
-        for (int i = 0; i < mTrackFormats.size(); i++) {
-            Format format = mTrackFormats.valueAt(i);
-            if (format.width != Format.NO_VALUE && format.height != Format.NO_VALUE) {
-                videoWidth = format.width;
-                videoHeight = format.height;
-                break;
-            }
-        }
-
-        String alteredParameters =
-                String.join(
-                        MEDIAMETRICS_ELEMENT_SEPARATOR,
-                        mParserParameters.keySet().toArray(new String[0]));
-        alteredParameters =
-                alteredParameters.substring(
-                        0,
-                        Math.min(
-                                alteredParameters.length(),
-                                MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH));
-
-        nativeSubmitMetrics(
-                SdkLevel.isAtLeastS() ? getLogSessionIdStringV31() : "",
-                mParserName,
-                mCreatedByName,
-                String.join(MEDIAMETRICS_ELEMENT_SEPARATOR, mParserNamesPool),
-                mLastObservedExceptionName,
-                addDither(mResourceByteCount),
-                addDither(mDurationMillis),
-                trackMimeTypes,
-                trackCodecs,
-                alteredParameters,
-                videoWidth,
-                videoHeight);
-    }
-
-    @RequiresApi(31)
-    public void setLogSessionId(@NonNull LogSessionId logSessionId) {
-        this.mLogSessionId = Objects.requireNonNull(logSessionId);
-    }
-
-    @RequiresApi(31)
-    @NonNull
-    public LogSessionId getLogSessionId() {
-        return mLogSessionId != null ? mLogSessionId : LogSessionId.LOG_SESSION_ID_NONE;
-    }
-
-    // Private methods.
-
-    private MediaParser(
-            OutputConsumer outputConsumer, boolean createdByName, String... parserNamesPool) {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
-            throw new UnsupportedOperationException("Android version must be R or greater.");
-        }
-        mParserParameters = new HashMap<>();
-        mOutputConsumer = outputConsumer;
-        mParserNamesPool = parserNamesPool;
-        mCreatedByName = createdByName;
-        mParserName = createdByName ? parserNamesPool[0] : PARSER_NAME_UNKNOWN;
-        mPositionHolder = new PositionHolder();
-        mExoDataReader = new InputReadingDataReader();
-        removePendingSeek();
-        mScratchDataReaderAdapter = new DataReaderAdapter();
-        mScratchParsableByteArrayAdapter = new ParsableByteArrayAdapter();
-        mSchemeInitDataConstructor = getSchemeInitDataConstructor();
-        mMuxedCaptionFormats = new ArrayList<>();
-
-        // MediaMetrics.
-        mTrackFormats = new SparseArray<>();
-        mLastObservedExceptionName = "";
-        mDurationMillis = -1;
-    }
-
-    private String buildMediaMetricsString(Function<Format, String> formatFieldGetter) {
-        StringBuilder stringBuilder = new StringBuilder();
-        for (int i = 0; i < mTrackFormats.size(); i++) {
-            if (i > 0) {
-                stringBuilder.append(MEDIAMETRICS_ELEMENT_SEPARATOR);
-            }
-            String fieldValue = formatFieldGetter.apply(mTrackFormats.valueAt(i));
-            stringBuilder.append(fieldValue != null ? fieldValue : "");
-        }
-        return stringBuilder.substring(
-                0, Math.min(stringBuilder.length(), MEDIAMETRICS_MAX_STRING_SIZE));
-    }
-
-    private void setMuxedCaptionFormats(List<MediaFormat> mediaFormats) {
-        mMuxedCaptionFormats.clear();
-        for (MediaFormat mediaFormat : mediaFormats) {
-            mMuxedCaptionFormats.add(toExoPlayerCaptionFormat(mediaFormat));
-        }
-    }
-
-    private boolean isPendingSeek() {
-        return mPendingSeekPosition >= 0;
-    }
-
-    private void removePendingSeek() {
-        mPendingSeekPosition = -1;
-        mPendingSeekTimeMicros = -1;
-    }
-
-    private Extractor createExtractor(String parserName) {
-        int flags = 0;
-        TimestampAdjuster timestampAdjuster = null;
-        if (mIgnoreTimestampOffset) {
-            timestampAdjuster = new TimestampAdjuster(TimestampAdjuster.DO_NOT_OFFSET);
-        }
-        switch (parserName) {
-            case PARSER_NAME_MATROSKA:
-                flags =
-                        getBooleanParameter(PARAMETER_MATROSKA_DISABLE_CUES_SEEKING)
-                                ? MatroskaExtractor.FLAG_DISABLE_SEEK_FOR_CUES
-                                : 0;
-                return new MatroskaExtractor(flags);
-            case PARSER_NAME_FMP4:
-                flags |=
-                        getBooleanParameter(PARAMETER_EXPOSE_EMSG_TRACK)
-                                ? FragmentedMp4Extractor.FLAG_ENABLE_EMSG_TRACK
-                                : 0;
-                flags |=
-                        getBooleanParameter(PARAMETER_MP4_IGNORE_EDIT_LISTS)
-                                ? FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS
-                                : 0;
-                flags |=
-                        getBooleanParameter(PARAMETER_MP4_IGNORE_TFDT_BOX)
-                                ? FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_TFDT_BOX
-                                : 0;
-                flags |=
-                        getBooleanParameter(PARAMETER_MP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES)
-                                ? FragmentedMp4Extractor
-                                        .FLAG_WORKAROUND_EVERY_VIDEO_FRAME_IS_SYNC_FRAME
-                                : 0;
-                return new FragmentedMp4Extractor(
-                        flags,
-                        timestampAdjuster,
-                        /* sideloadedTrack= */ null,
-                        mMuxedCaptionFormats);
-            case PARSER_NAME_MP4:
-                flags |=
-                        getBooleanParameter(PARAMETER_MP4_IGNORE_EDIT_LISTS)
-                                ? Mp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS
-                                : 0;
-                return new Mp4Extractor(flags);
-            case PARSER_NAME_MP3:
-                flags |=
-                        getBooleanParameter(PARAMETER_MP3_DISABLE_ID3)
-                                ? Mp3Extractor.FLAG_DISABLE_ID3_METADATA
-                                : 0;
-                flags |=
-                        getBooleanParameter(PARAMETER_MP3_ENABLE_CBR_SEEKING)
-                                ? Mp3Extractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
-                                : 0;
-                // TODO: Add index seeking once we update the ExoPlayer version.
-                return new Mp3Extractor(flags);
-            case PARSER_NAME_ADTS:
-                flags |=
-                        getBooleanParameter(PARAMETER_ADTS_ENABLE_CBR_SEEKING)
-                                ? AdtsExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
-                                : 0;
-                return new AdtsExtractor(flags);
-            case PARSER_NAME_AC3:
-                return new Ac3Extractor();
-            case PARSER_NAME_TS:
-                flags |=
-                        getBooleanParameter(PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES)
-                                ? DefaultTsPayloadReaderFactory.FLAG_ALLOW_NON_IDR_KEYFRAMES
-                                : 0;
-                flags |=
-                        getBooleanParameter(PARAMETER_TS_DETECT_ACCESS_UNITS)
-                                ? DefaultTsPayloadReaderFactory.FLAG_DETECT_ACCESS_UNITS
-                                : 0;
-                flags |=
-                        getBooleanParameter(PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS)
-                                ? DefaultTsPayloadReaderFactory.FLAG_ENABLE_HDMV_DTS_AUDIO_STREAMS
-                                : 0;
-                flags |=
-                        getBooleanParameter(PARAMETER_TS_IGNORE_AAC_STREAM)
-                                ? DefaultTsPayloadReaderFactory.FLAG_IGNORE_AAC_STREAM
-                                : 0;
-                flags |=
-                        getBooleanParameter(PARAMETER_TS_IGNORE_AVC_STREAM)
-                                ? DefaultTsPayloadReaderFactory.FLAG_IGNORE_H264_STREAM
-                                : 0;
-                flags |=
-                        getBooleanParameter(PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM)
-                                ? DefaultTsPayloadReaderFactory.FLAG_IGNORE_SPLICE_INFO_STREAM
-                                : 0;
-                flags |=
-                        getBooleanParameter(PARAMETER_OVERRIDE_IN_BAND_CAPTION_DECLARATIONS)
-                                ? DefaultTsPayloadReaderFactory.FLAG_OVERRIDE_CAPTION_DESCRIPTORS
-                                : 0;
-                String tsMode = getStringParameter(PARAMETER_TS_MODE, TS_MODE_SINGLE_PMT);
-                int hlsMode =
-                        TS_MODE_SINGLE_PMT.equals(tsMode)
-                                ? TsExtractor.MODE_SINGLE_PMT
-                                : TS_MODE_HLS.equals(tsMode)
-                                        ? TsExtractor.MODE_HLS
-                                        : TsExtractor.MODE_MULTI_PMT;
-                return new TsExtractor(
-                        hlsMode,
-                        timestampAdjuster != null
-                                ? timestampAdjuster
-                                : new TimestampAdjuster(/* firstSampleTimestampUs= */ 0),
-                        new DefaultTsPayloadReaderFactory(flags, mMuxedCaptionFormats));
-            case PARSER_NAME_FLV:
-                return new FlvExtractor();
-            case PARSER_NAME_OGG:
-                return new OggExtractor();
-            case PARSER_NAME_PS:
-                return new PsExtractor();
-            case PARSER_NAME_WAV:
-                return new WavExtractor();
-            case PARSER_NAME_AMR:
-                flags |=
-                        getBooleanParameter(PARAMETER_AMR_ENABLE_CBR_SEEKING)
-                                ? AmrExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
-                                : 0;
-                return new AmrExtractor(flags);
-            case PARSER_NAME_AC4:
-                return new Ac4Extractor();
-            case PARSER_NAME_FLAC:
-                flags |=
-                        getBooleanParameter(PARAMETER_FLAC_DISABLE_ID3)
-                                ? FlacExtractor.FLAG_DISABLE_ID3_METADATA
-                                : 0;
-                return new FlacExtractor(flags);
-            default:
-                // Should never happen.
-                throw new IllegalStateException("Unexpected attempt to create: " + parserName);
-        }
-    }
-
-    private boolean getBooleanParameter(String name) {
-        return (boolean) mParserParameters.getOrDefault(name, false);
-    }
-
-    private String getStringParameter(String name, String defaultValue) {
-        return (String) mParserParameters.getOrDefault(name, defaultValue);
-    }
-
-    @RequiresApi(31)
-    private String getLogSessionIdStringV31() {
-        return mLogSessionId != null ? mLogSessionId.getStringId() : "";
-    }
-
-    // Private classes.
-
-    private static final class InputReadingDataReader implements DataReader {
-
-        public InputReader mInputReader;
-
-        @Override
-        public int read(byte[] buffer, int offset, int readLength) throws IOException {
-            return mInputReader.read(buffer, offset, readLength);
-        }
-    }
-
-    private final class MediaParserDrmInitData extends DrmInitData {
-
-        private final SchemeInitData[] mSchemeDatas;
-
-        private MediaParserDrmInitData(com.google.android.exoplayer2.drm.DrmInitData exoDrmInitData)
-                throws IllegalAccessException, InstantiationException, InvocationTargetException {
-            mSchemeDatas = new SchemeInitData[exoDrmInitData.schemeDataCount];
-            for (int i = 0; i < mSchemeDatas.length; i++) {
-                mSchemeDatas[i] = toFrameworkSchemeInitData(exoDrmInitData.get(i));
-            }
-        }
-
-        @Override
-        @Nullable
-        public SchemeInitData get(UUID schemeUuid) {
-            for (SchemeInitData schemeInitData : mSchemeDatas) {
-                if (schemeInitData.uuid.equals(schemeUuid)) {
-                    return schemeInitData;
-                }
-            }
-            return null;
-        }
-
-        @Override
-        public SchemeInitData getSchemeInitDataAt(int index) {
-            return mSchemeDatas[index];
-        }
-
-        @Override
-        public int getSchemeInitDataCount() {
-            return mSchemeDatas.length;
-        }
-
-        private DrmInitData.SchemeInitData toFrameworkSchemeInitData(SchemeData exoSchemeData)
-                throws IllegalAccessException, InvocationTargetException, InstantiationException {
-            return mSchemeInitDataConstructor.newInstance(
-                    exoSchemeData.uuid, exoSchemeData.mimeType, exoSchemeData.data);
-        }
-    }
-
-    private final class ExtractorOutputAdapter implements ExtractorOutput {
-
-        private final SparseArray<TrackOutput> mTrackOutputAdapters;
-        private boolean mTracksEnded;
-
-        private ExtractorOutputAdapter() {
-            mTrackOutputAdapters = new SparseArray<>();
-        }
-
-        @Override
-        public TrackOutput track(int id, int type) {
-            TrackOutput trackOutput = mTrackOutputAdapters.get(id);
-            if (trackOutput == null) {
-                int trackIndex = mTrackOutputAdapters.size();
-                trackOutput = new TrackOutputAdapter(trackIndex);
-                mTrackOutputAdapters.put(id, trackOutput);
-                if (mEagerlyExposeTrackType) {
-                    MediaFormat mediaFormat = new MediaFormat();
-                    mediaFormat.setString("track-type-string", toTypeString(type));
-                    mOutputConsumer.onTrackDataFound(
-                            trackIndex, new TrackData(mediaFormat, /* drmInitData= */ null));
-                }
-            }
-            return trackOutput;
-        }
-
-        @Override
-        public void endTracks() {
-            mOutputConsumer.onTrackCountFound(mTrackOutputAdapters.size());
-        }
-
-        @Override
-        public void seekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
-            long durationUs = exoplayerSeekMap.getDurationUs();
-            if (durationUs != C.TIME_UNSET) {
-                mDurationMillis = C.usToMs(durationUs);
-            }
-            if (mExposeChunkIndexAsMediaFormat && exoplayerSeekMap instanceof ChunkIndex) {
-                ChunkIndex chunkIndex = (ChunkIndex) exoplayerSeekMap;
-                MediaFormat mediaFormat = new MediaFormat();
-                mediaFormat.setByteBuffer("chunk-index-int-sizes", toByteBuffer(chunkIndex.sizes));
-                mediaFormat.setByteBuffer(
-                        "chunk-index-long-offsets", toByteBuffer(chunkIndex.offsets));
-                mediaFormat.setByteBuffer(
-                        "chunk-index-long-us-durations", toByteBuffer(chunkIndex.durationsUs));
-                mediaFormat.setByteBuffer(
-                        "chunk-index-long-us-times", toByteBuffer(chunkIndex.timesUs));
-                mOutputConsumer.onTrackDataFound(
-                        /* trackIndex= */ 0, new TrackData(mediaFormat, /* drmInitData= */ null));
-            }
-            mOutputConsumer.onSeekMapFound(new SeekMap(exoplayerSeekMap));
-        }
-    }
-
-    private class TrackOutputAdapter implements TrackOutput {
-
-        private final int mTrackIndex;
-
-        private CryptoInfo mLastOutputCryptoInfo;
-        private CryptoInfo.Pattern mLastOutputEncryptionPattern;
-        private CryptoData mLastReceivedCryptoData;
-
-        @EncryptionDataReadState private int mEncryptionDataReadState;
-        private int mEncryptionDataSizeToSubtractFromSampleDataSize;
-        private int mEncryptionVectorSize;
-        private byte[] mScratchIvSpace;
-        private int mSubsampleEncryptionDataSize;
-        private int[] mScratchSubsampleEncryptedBytesCount;
-        private int[] mScratchSubsampleClearBytesCount;
-        private boolean mHasSubsampleEncryptionData;
-        private int mSkippedSupplementalDataBytes;
-
-        private TrackOutputAdapter(int trackIndex) {
-            mTrackIndex = trackIndex;
-            mScratchIvSpace = new byte[16]; // Size documented in CryptoInfo.
-            mScratchSubsampleEncryptedBytesCount = new int[32];
-            mScratchSubsampleClearBytesCount = new int[32];
-            mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE;
-            mLastOutputEncryptionPattern =
-                    new CryptoInfo.Pattern(/* blocksToEncrypt= */ 0, /* blocksToSkip= */ 0);
-        }
-
-        @Override
-        public void format(Format format) {
-            mTrackFormats.put(mTrackIndex, format);
-            mOutputConsumer.onTrackDataFound(
-                    mTrackIndex,
-                    new TrackData(
-                            toMediaFormat(format), toFrameworkDrmInitData(format.drmInitData)));
-        }
-
-        @Override
-        public int sampleData(
-                DataReader input,
-                int length,
-                boolean allowEndOfInput,
-                @SampleDataPart int sampleDataPart)
-                throws IOException {
-            mScratchDataReaderAdapter.setDataReader(input, length);
-            long positionBeforeReading = mScratchDataReaderAdapter.getPosition();
-            mOutputConsumer.onSampleDataFound(mTrackIndex, mScratchDataReaderAdapter);
-            return (int) (mScratchDataReaderAdapter.getPosition() - positionBeforeReading);
-        }
-
-        @Override
-        public void sampleData(
-                ParsableByteArray data, int length, @SampleDataPart int sampleDataPart) {
-            if (sampleDataPart == SAMPLE_DATA_PART_ENCRYPTION && !mInBandCryptoInfo) {
-                while (length > 0) {
-                    switch (mEncryptionDataReadState) {
-                        case STATE_READING_SIGNAL_BYTE:
-                            int encryptionSignalByte = data.readUnsignedByte();
-                            length--;
-                            mHasSubsampleEncryptionData = ((encryptionSignalByte >> 7) & 1) != 0;
-                            mEncryptionVectorSize = encryptionSignalByte & 0x7F;
-                            mEncryptionDataSizeToSubtractFromSampleDataSize =
-                                    mEncryptionVectorSize + 1; // Signal byte.
-                            mEncryptionDataReadState = STATE_READING_INIT_VECTOR;
-                            break;
-                        case STATE_READING_INIT_VECTOR:
-                            Arrays.fill(mScratchIvSpace, (byte) 0); // Ensure 0-padding.
-                            data.readBytes(mScratchIvSpace, /* offset= */ 0, mEncryptionVectorSize);
-                            length -= mEncryptionVectorSize;
-                            if (mHasSubsampleEncryptionData) {
-                                mEncryptionDataReadState = STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE;
-                            } else {
-                                mSubsampleEncryptionDataSize = 0;
-                                mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE;
-                            }
-                            break;
-                        case STATE_READING_SUBSAMPLE_ENCRYPTION_SIZE:
-                            mSubsampleEncryptionDataSize = data.readUnsignedShort();
-                            if (mScratchSubsampleClearBytesCount.length
-                                    < mSubsampleEncryptionDataSize) {
-                                mScratchSubsampleClearBytesCount =
-                                        new int[mSubsampleEncryptionDataSize];
-                                mScratchSubsampleEncryptedBytesCount =
-                                        new int[mSubsampleEncryptionDataSize];
-                            }
-                            length -= 2;
-                            mEncryptionDataSizeToSubtractFromSampleDataSize +=
-                                    2
-                                            + mSubsampleEncryptionDataSize
-                                                    * BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY;
-                            mEncryptionDataReadState = STATE_READING_SUBSAMPLE_ENCRYPTION_DATA;
-                            break;
-                        case STATE_READING_SUBSAMPLE_ENCRYPTION_DATA:
-                            for (int i = 0; i < mSubsampleEncryptionDataSize; i++) {
-                                mScratchSubsampleClearBytesCount[i] = data.readUnsignedShort();
-                                mScratchSubsampleEncryptedBytesCount[i] = data.readInt();
-                            }
-                            length -=
-                                    mSubsampleEncryptionDataSize
-                                            * BYTES_PER_SUBSAMPLE_ENCRYPTION_ENTRY;
-                            mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE;
-                            if (length != 0) {
-                                throw new IllegalStateException();
-                            }
-                            break;
-                        default:
-                            // Never happens.
-                            throw new IllegalStateException();
-                    }
-                }
-            } else if (sampleDataPart == SAMPLE_DATA_PART_SUPPLEMENTAL
-                    && !mIncludeSupplementalData) {
-                mSkippedSupplementalDataBytes += length;
-                data.skipBytes(length);
-            } else {
-                outputSampleData(data, length);
-            }
-        }
-
-        @Override
-        public void sampleMetadata(
-                long timeUs, int flags, int size, int offset, @Nullable CryptoData cryptoData) {
-            size -= mSkippedSupplementalDataBytes;
-            mSkippedSupplementalDataBytes = 0;
-            mOutputConsumer.onSampleCompleted(
-                    mTrackIndex,
-                    timeUs,
-                    getMediaParserFlags(flags),
-                    size - mEncryptionDataSizeToSubtractFromSampleDataSize,
-                    offset,
-                    getPopulatedCryptoInfo(cryptoData));
-            mEncryptionDataReadState = STATE_READING_SIGNAL_BYTE;
-            mEncryptionDataSizeToSubtractFromSampleDataSize = 0;
-        }
-
-        @Nullable
-        private CryptoInfo getPopulatedCryptoInfo(@Nullable CryptoData cryptoData) {
-            if (cryptoData == null) {
-                // The sample is not encrypted.
-                return null;
-            } else if (mInBandCryptoInfo) {
-                if (cryptoData != mLastReceivedCryptoData) {
-                    mLastOutputCryptoInfo =
-                            createNewCryptoInfoAndPopulateWithCryptoData(cryptoData);
-                    // We are using in-band crypto info, so the IV will be ignored. But we prevent
-                    // it from being null because toString assumes it non-null.
-                    mLastOutputCryptoInfo.iv = EMPTY_BYTE_ARRAY;
-                }
-            } else /* We must populate the full CryptoInfo. */ {
-                // CryptoInfo.pattern is not accessible to the user, so the user needs to feed
-                // this CryptoInfo directly to MediaCodec. We need to create a new CryptoInfo per
-                // sample because of per-sample initialization vector changes.
-                CryptoInfo newCryptoInfo = createNewCryptoInfoAndPopulateWithCryptoData(cryptoData);
-                newCryptoInfo.iv = Arrays.copyOf(mScratchIvSpace, mScratchIvSpace.length);
-                boolean canReuseSubsampleInfo =
-                        mLastOutputCryptoInfo != null
-                                && mLastOutputCryptoInfo.numSubSamples
-                                        == mSubsampleEncryptionDataSize;
-                for (int i = 0; i < mSubsampleEncryptionDataSize && canReuseSubsampleInfo; i++) {
-                    canReuseSubsampleInfo =
-                            mLastOutputCryptoInfo.numBytesOfClearData[i]
-                                            == mScratchSubsampleClearBytesCount[i]
-                                    && mLastOutputCryptoInfo.numBytesOfEncryptedData[i]
-                                            == mScratchSubsampleEncryptedBytesCount[i];
-                }
-                newCryptoInfo.numSubSamples = mSubsampleEncryptionDataSize;
-                if (canReuseSubsampleInfo) {
-                    newCryptoInfo.numBytesOfClearData = mLastOutputCryptoInfo.numBytesOfClearData;
-                    newCryptoInfo.numBytesOfEncryptedData =
-                            mLastOutputCryptoInfo.numBytesOfEncryptedData;
-                } else {
-                    newCryptoInfo.numBytesOfClearData =
-                            Arrays.copyOf(
-                                    mScratchSubsampleClearBytesCount, mSubsampleEncryptionDataSize);
-                    newCryptoInfo.numBytesOfEncryptedData =
-                            Arrays.copyOf(
-                                    mScratchSubsampleEncryptedBytesCount,
-                                    mSubsampleEncryptionDataSize);
-                }
-                mLastOutputCryptoInfo = newCryptoInfo;
-            }
-            mLastReceivedCryptoData = cryptoData;
-            return mLastOutputCryptoInfo;
-        }
-
-        private CryptoInfo createNewCryptoInfoAndPopulateWithCryptoData(CryptoData cryptoData) {
-            CryptoInfo cryptoInfo = new CryptoInfo();
-            cryptoInfo.key = cryptoData.encryptionKey;
-            cryptoInfo.mode = cryptoData.cryptoMode;
-            if (cryptoData.clearBlocks != mLastOutputEncryptionPattern.getSkipBlocks()
-                    || cryptoData.encryptedBlocks
-                            != mLastOutputEncryptionPattern.getEncryptBlocks()) {
-                mLastOutputEncryptionPattern =
-                        new CryptoInfo.Pattern(cryptoData.encryptedBlocks, cryptoData.clearBlocks);
-            }
-            cryptoInfo.setPattern(mLastOutputEncryptionPattern);
-            return cryptoInfo;
-        }
-
-        private void outputSampleData(ParsableByteArray data, int length) {
-            mScratchParsableByteArrayAdapter.resetWithByteArray(data, length);
-            try {
-                // Read all bytes from data. ExoPlayer extractors expect all sample data to be
-                // consumed by TrackOutput implementations when passing a ParsableByteArray.
-                while (mScratchParsableByteArrayAdapter.getLength() > 0) {
-                    mOutputConsumer.onSampleDataFound(
-                            mTrackIndex, mScratchParsableByteArrayAdapter);
-                }
-            } catch (IOException e) {
-                // Unexpected.
-                throw new RuntimeException(e);
-            }
-        }
-    }
-
-    private static final class DataReaderAdapter implements InputReader {
-
-        private DataReader mDataReader;
-        private int mCurrentPosition;
-        private long mLength;
-
-        public void setDataReader(DataReader dataReader, long length) {
-            mDataReader = dataReader;
-            mCurrentPosition = 0;
-            mLength = length;
-        }
-
-        // Input implementation.
-
-        @Override
-        public int read(byte[] buffer, int offset, int readLength) throws IOException {
-            int readBytes = 0;
-            readBytes = mDataReader.read(buffer, offset, readLength);
-            mCurrentPosition += readBytes;
-            return readBytes;
-        }
-
-        @Override
-        public long getPosition() {
-            return mCurrentPosition;
-        }
-
-        @Override
-        public long getLength() {
-            return mLength - mCurrentPosition;
-        }
-    }
-
-    private static final class ParsableByteArrayAdapter implements InputReader {
-
-        private ParsableByteArray mByteArray;
-        private long mLength;
-        private int mCurrentPosition;
-
-        public void resetWithByteArray(ParsableByteArray byteArray, long length) {
-            mByteArray = byteArray;
-            mCurrentPosition = 0;
-            mLength = length;
-        }
-
-        // Input implementation.
-
-        @Override
-        public int read(byte[] buffer, int offset, int readLength) {
-            mByteArray.readBytes(buffer, offset, readLength);
-            mCurrentPosition += readLength;
-            return readLength;
-        }
-
-        @Override
-        public long getPosition() {
-            return mCurrentPosition;
-        }
-
-        @Override
-        public long getLength() {
-            return mLength - mCurrentPosition;
-        }
-    }
-
-    private static final class DummyExoPlayerSeekMap
-            implements com.google.android.exoplayer2.extractor.SeekMap {
-
-        @Override
-        public boolean isSeekable() {
-            return true;
-        }
-
-        @Override
-        public long getDurationUs() {
-            return C.TIME_UNSET;
-        }
-
-        @Override
-        public SeekPoints getSeekPoints(long timeUs) {
-            com.google.android.exoplayer2.extractor.SeekPoint seekPoint =
-                    new com.google.android.exoplayer2.extractor.SeekPoint(
-                            timeUs, /* position= */ 0);
-            return new SeekPoints(seekPoint, seekPoint);
-        }
-    }
-
-    /** Creates extractor instances. */
-    private interface ExtractorFactory {
-
-        /** Returns a new extractor instance. */
-        Extractor createInstance();
-    }
-
-    // Private static methods.
-
-    private static Format toExoPlayerCaptionFormat(MediaFormat mediaFormat) {
-        Format.Builder formatBuilder =
-                new Format.Builder().setSampleMimeType(mediaFormat.getString(MediaFormat.KEY_MIME));
-        if (mediaFormat.containsKey(MediaFormat.KEY_CAPTION_SERVICE_NUMBER)) {
-            formatBuilder.setAccessibilityChannel(
-                    mediaFormat.getInteger(MediaFormat.KEY_CAPTION_SERVICE_NUMBER));
-        }
-        return formatBuilder.build();
-    }
-
-    private static MediaFormat toMediaFormat(Format format) {
-        MediaFormat result = new MediaFormat();
-        setOptionalMediaFormatInt(result, MediaFormat.KEY_BIT_RATE, format.bitrate);
-        setOptionalMediaFormatInt(result, MediaFormat.KEY_CHANNEL_COUNT, format.channelCount);
-
-        ColorInfo colorInfo = format.colorInfo;
-        if (colorInfo != null) {
-            setOptionalMediaFormatInt(
-                    result, MediaFormat.KEY_COLOR_TRANSFER, colorInfo.colorTransfer);
-            setOptionalMediaFormatInt(result, MediaFormat.KEY_COLOR_RANGE, colorInfo.colorRange);
-            setOptionalMediaFormatInt(result, MediaFormat.KEY_COLOR_STANDARD, colorInfo.colorSpace);
-
-            if (format.colorInfo.hdrStaticInfo != null) {
-                result.setByteBuffer(
-                        MediaFormat.KEY_HDR_STATIC_INFO,
-                        ByteBuffer.wrap(format.colorInfo.hdrStaticInfo));
-            }
-        }
-
-        setOptionalMediaFormatString(result, MediaFormat.KEY_MIME, format.sampleMimeType);
-        setOptionalMediaFormatString(result, MediaFormat.KEY_CODECS_STRING, format.codecs);
-        if (format.frameRate != Format.NO_VALUE) {
-            result.setFloat(MediaFormat.KEY_FRAME_RATE, format.frameRate);
-        }
-        setOptionalMediaFormatInt(result, MediaFormat.KEY_WIDTH, format.width);
-        setOptionalMediaFormatInt(result, MediaFormat.KEY_HEIGHT, format.height);
-
-        List<byte[]> initData = format.initializationData;
-        for (int i = 0; i < initData.size(); i++) {
-            result.setByteBuffer("csd-" + i, ByteBuffer.wrap(initData.get(i)));
-        }
-        setPcmEncoding(format, result);
-        setOptionalMediaFormatString(result, MediaFormat.KEY_LANGUAGE, format.language);
-        setOptionalMediaFormatInt(result, MediaFormat.KEY_MAX_INPUT_SIZE, format.maxInputSize);
-        setOptionalMediaFormatInt(result, MediaFormat.KEY_ROTATION, format.rotationDegrees);
-        setOptionalMediaFormatInt(result, MediaFormat.KEY_SAMPLE_RATE, format.sampleRate);
-        setOptionalMediaFormatInt(
-                result, MediaFormat.KEY_CAPTION_SERVICE_NUMBER, format.accessibilityChannel);
-
-        int selectionFlags = format.selectionFlags;
-        result.setInteger(
-                MediaFormat.KEY_IS_AUTOSELECT, selectionFlags & C.SELECTION_FLAG_AUTOSELECT);
-        result.setInteger(MediaFormat.KEY_IS_DEFAULT, selectionFlags & C.SELECTION_FLAG_DEFAULT);
-        result.setInteger(
-                MediaFormat.KEY_IS_FORCED_SUBTITLE, selectionFlags & C.SELECTION_FLAG_FORCED);
-
-        setOptionalMediaFormatInt(result, MediaFormat.KEY_ENCODER_DELAY, format.encoderDelay);
-        setOptionalMediaFormatInt(result, MediaFormat.KEY_ENCODER_PADDING, format.encoderPadding);
-
-        if (format.pixelWidthHeightRatio != Format.NO_VALUE && format.pixelWidthHeightRatio != 0) {
-            int parWidth = 1;
-            int parHeight = 1;
-            if (format.pixelWidthHeightRatio < 1.0f) {
-                parHeight = 1 << 30;
-                parWidth = (int) (format.pixelWidthHeightRatio * parHeight);
-            } else if (format.pixelWidthHeightRatio > 1.0f) {
-                parWidth = 1 << 30;
-                parHeight = (int) (parWidth / format.pixelWidthHeightRatio);
-            }
-            result.setInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH, parWidth);
-            result.setInteger(MediaFormat.KEY_PIXEL_ASPECT_RATIO_HEIGHT, parHeight);
-            result.setFloat("pixel-width-height-ratio-float", format.pixelWidthHeightRatio);
-        }
-        if (format.drmInitData != null) {
-            // The crypto mode is propagated along with sample metadata. We also include it in the
-            // format for convenient use from ExoPlayer.
-            result.setString("crypto-mode-fourcc", format.drmInitData.schemeType);
-        }
-        if (format.subsampleOffsetUs != Format.OFFSET_SAMPLE_RELATIVE) {
-            result.setLong("subsample-offset-us-long", format.subsampleOffsetUs);
-        }
-        // LACK OF SUPPORT FOR:
-        //    format.id;
-        //    format.metadata;
-        //    format.stereoMode;
-        return result;
-    }
-
-    private static ByteBuffer toByteBuffer(long[] longArray) {
-        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(longArray.length * Long.BYTES);
-        for (long element : longArray) {
-            byteBuffer.putLong(element);
-        }
-        byteBuffer.flip();
-        return byteBuffer;
-    }
-
-    private static ByteBuffer toByteBuffer(int[] intArray) {
-        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(intArray.length * Integer.BYTES);
-        for (int element : intArray) {
-            byteBuffer.putInt(element);
-        }
-        byteBuffer.flip();
-        return byteBuffer;
-    }
-
-    private static String toTypeString(int type) {
-        switch (type) {
-            case C.TRACK_TYPE_VIDEO:
-                return "video";
-            case C.TRACK_TYPE_AUDIO:
-                return "audio";
-            case C.TRACK_TYPE_TEXT:
-                return "text";
-            case C.TRACK_TYPE_METADATA:
-                return "metadata";
-            default:
-                return "unknown";
-        }
-    }
-
-    private static void setPcmEncoding(Format format, MediaFormat result) {
-        int exoPcmEncoding = format.pcmEncoding;
-        setOptionalMediaFormatInt(result, "exo-pcm-encoding", format.pcmEncoding);
-        int mediaFormatPcmEncoding;
-        switch (exoPcmEncoding) {
-            case C.ENCODING_PCM_8BIT:
-                mediaFormatPcmEncoding = AudioFormat.ENCODING_PCM_8BIT;
-                break;
-            case C.ENCODING_PCM_16BIT:
-                mediaFormatPcmEncoding = AudioFormat.ENCODING_PCM_16BIT;
-                break;
-            case C.ENCODING_PCM_FLOAT:
-                mediaFormatPcmEncoding = AudioFormat.ENCODING_PCM_FLOAT;
-                break;
-            default:
-                // No matching value. Do nothing.
-                return;
-        }
-        result.setInteger(MediaFormat.KEY_PCM_ENCODING, mediaFormatPcmEncoding);
-    }
-
-    private static void setOptionalMediaFormatInt(MediaFormat mediaFormat, String key, int value) {
-        if (value != Format.NO_VALUE) {
-            mediaFormat.setInteger(key, value);
-        }
-    }
-
-    private static void setOptionalMediaFormatString(
-            MediaFormat mediaFormat, String key, @Nullable String value) {
-        if (value != null) {
-            mediaFormat.setString(key, value);
-        }
-    }
-
-    private DrmInitData toFrameworkDrmInitData(
-            com.google.android.exoplayer2.drm.DrmInitData exoDrmInitData) {
-        try {
-            return exoDrmInitData != null && mSchemeInitDataConstructor != null
-                    ? new MediaParserDrmInitData(exoDrmInitData)
-                    : null;
-        } catch (Throwable e) {
-            if (!mLoggedSchemeInitDataCreationException) {
-                mLoggedSchemeInitDataCreationException = true;
-                Log.e(TAG, "Unable to create SchemeInitData instance.");
-            }
-            return null;
-        }
-    }
-
-    /** Returns a new {@link SeekPoint} equivalent to the given {@code exoPlayerSeekPoint}. */
-    private static SeekPoint toSeekPoint(
-            com.google.android.exoplayer2.extractor.SeekPoint exoPlayerSeekPoint) {
-        return new SeekPoint(exoPlayerSeekPoint.timeUs, exoPlayerSeekPoint.position);
-    }
-
-    /**
-     * Introduces random error to the given metric value in order to prevent the identification of
-     * the parsed media.
-     */
-    private static long addDither(long value) {
-        // Generate a random in [0, 1].
-        double randomDither = ThreadLocalRandom.current().nextFloat();
-        // Clamp the random number to [0, 2 * MEDIAMETRICS_DITHER].
-        randomDither *= 2 * MEDIAMETRICS_DITHER;
-        // Translate the random number to [1 - MEDIAMETRICS_DITHER, 1 + MEDIAMETRICS_DITHER].
-        randomDither += 1 - MEDIAMETRICS_DITHER;
-        return value != -1 ? (long) (value * randomDither) : -1;
-    }
-
-    private static void assertValidNames(@NonNull String[] names) {
-        for (String name : names) {
-            if (!EXTRACTOR_FACTORIES_BY_NAME.containsKey(name)) {
-                throw new IllegalArgumentException(
-                        "Invalid extractor name: "
-                                + name
-                                + ". Supported parsers are: "
-                                + TextUtils.join(", ", EXTRACTOR_FACTORIES_BY_NAME.keySet())
-                                + ".");
-            }
-        }
-    }
-
-    private int getMediaParserFlags(int flags) {
-        @SampleFlags int result = 0;
-        result |= (flags & C.BUFFER_FLAG_ENCRYPTED) != 0 ? SAMPLE_FLAG_ENCRYPTED : 0;
-        result |= (flags & C.BUFFER_FLAG_KEY_FRAME) != 0 ? SAMPLE_FLAG_KEY_FRAME : 0;
-        result |= (flags & C.BUFFER_FLAG_DECODE_ONLY) != 0 ? SAMPLE_FLAG_DECODE_ONLY : 0;
-        result |=
-                (flags & C.BUFFER_FLAG_HAS_SUPPLEMENTAL_DATA) != 0 && mIncludeSupplementalData
-                        ? SAMPLE_FLAG_HAS_SUPPLEMENTAL_DATA
-                        : 0;
-        result |= (flags & C.BUFFER_FLAG_LAST_SAMPLE) != 0 ? SAMPLE_FLAG_LAST_SAMPLE : 0;
-        return result;
-    }
-
-    @Nullable
-    private static Constructor<DrmInitData.SchemeInitData> getSchemeInitDataConstructor() {
-        // TODO: Use constructor statically when available.
-        Constructor<DrmInitData.SchemeInitData> constructor;
-        try {
-            return DrmInitData.SchemeInitData.class.getConstructor(
-                    UUID.class, String.class, byte[].class);
-        } catch (Throwable e) {
-            Log.e(TAG, "Unable to get SchemeInitData constructor.");
-            return null;
-        }
-    }
-
-    // Native methods.
-
-    private native void nativeSubmitMetrics(
-            String logSessionId,
-            String parserName,
-            boolean createdByName,
-            String parserPool,
-            String lastObservedExceptionName,
-            long resourceByteCount,
-            long durationMillis,
-            String trackMimeTypes,
-            String trackCodecs,
-            String alteredParameters,
-            int videoWidth,
-            int videoHeight);
-
-    // Static initialization.
-
-    static {
-        System.loadLibrary(JNI_LIBRARY_NAME);
-
-        // Using a LinkedHashMap to keep the insertion order when iterating over the keys.
-        LinkedHashMap<String, ExtractorFactory> extractorFactoriesByName = new LinkedHashMap<>();
-        // Parsers are ordered to match ExoPlayer's DefaultExtractorsFactory extractor ordering,
-        // which in turn aims to minimize the chances of incorrect extractor selections.
-        extractorFactoriesByName.put(PARSER_NAME_MATROSKA, MatroskaExtractor::new);
-        extractorFactoriesByName.put(PARSER_NAME_FMP4, FragmentedMp4Extractor::new);
-        extractorFactoriesByName.put(PARSER_NAME_MP4, Mp4Extractor::new);
-        extractorFactoriesByName.put(PARSER_NAME_MP3, Mp3Extractor::new);
-        extractorFactoriesByName.put(PARSER_NAME_ADTS, AdtsExtractor::new);
-        extractorFactoriesByName.put(PARSER_NAME_AC3, Ac3Extractor::new);
-        extractorFactoriesByName.put(PARSER_NAME_TS, TsExtractor::new);
-        extractorFactoriesByName.put(PARSER_NAME_FLV, FlvExtractor::new);
-        extractorFactoriesByName.put(PARSER_NAME_OGG, OggExtractor::new);
-        extractorFactoriesByName.put(PARSER_NAME_PS, PsExtractor::new);
-        extractorFactoriesByName.put(PARSER_NAME_WAV, WavExtractor::new);
-        extractorFactoriesByName.put(PARSER_NAME_AMR, AmrExtractor::new);
-        extractorFactoriesByName.put(PARSER_NAME_AC4, Ac4Extractor::new);
-        extractorFactoriesByName.put(PARSER_NAME_FLAC, FlacExtractor::new);
-        EXTRACTOR_FACTORIES_BY_NAME = Collections.unmodifiableMap(extractorFactoriesByName);
-
-        HashMap<String, Class> expectedTypeByParameterName = new HashMap<>();
-        expectedTypeByParameterName.put(PARAMETER_ADTS_ENABLE_CBR_SEEKING, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_AMR_ENABLE_CBR_SEEKING, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_FLAC_DISABLE_ID3, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_MP4_IGNORE_EDIT_LISTS, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_MP4_IGNORE_TFDT_BOX, Boolean.class);
-        expectedTypeByParameterName.put(
-                PARAMETER_MP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_MATROSKA_DISABLE_CUES_SEEKING, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_MP3_DISABLE_ID3, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_MP3_ENABLE_CBR_SEEKING, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_MP3_ENABLE_INDEX_SEEKING, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_TS_MODE, String.class);
-        expectedTypeByParameterName.put(PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_TS_IGNORE_AAC_STREAM, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_TS_IGNORE_AVC_STREAM, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_TS_DETECT_ACCESS_UNITS, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_IN_BAND_CRYPTO_INFO, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_INCLUDE_SUPPLEMENTAL_DATA, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_IGNORE_TIMESTAMP_OFFSET, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_EAGERLY_EXPOSE_TRACKTYPE, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_EXPOSE_DUMMY_SEEKMAP, Boolean.class);
-        expectedTypeByParameterName.put(
-                PARAMETER_EXPOSE_CHUNK_INDEX_AS_MEDIA_FORMAT, Boolean.class);
-        expectedTypeByParameterName.put(
-                PARAMETER_OVERRIDE_IN_BAND_CAPTION_DECLARATIONS, Boolean.class);
-        expectedTypeByParameterName.put(PARAMETER_EXPOSE_EMSG_TRACK, Boolean.class);
-        // We do not check PARAMETER_EXPOSE_CAPTION_FORMATS here, and we do it in setParameters
-        // instead. Checking that the value is a List is insufficient to catch wrong parameter
-        // value types.
-        int sumOfParameterNameLengths =
-                expectedTypeByParameterName.keySet().stream()
-                        .map(String::length)
-                        .reduce(0, Integer::sum);
-        sumOfParameterNameLengths += PARAMETER_EXPOSE_CAPTION_FORMATS.length();
-        // Add space for any required separators.
-        MEDIAMETRICS_PARAMETER_LIST_MAX_LENGTH =
-                sumOfParameterNameLengths + expectedTypeByParameterName.size();
-
-        EXPECTED_TYPE_BY_PARAMETER_NAME = Collections.unmodifiableMap(expectedTypeByParameterName);
-    }
-}
diff --git a/apex/media/framework/java/android/media/MediaSession2.java b/apex/media/framework/java/android/media/MediaSession2.java
deleted file mode 100644
index 7d07eb3..0000000
--- a/apex/media/framework/java/android/media/MediaSession2.java
+++ /dev/null
@@ -1,932 +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 android.media;
-
-import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS;
-import static android.media.MediaConstants.KEY_CONNECTION_HINTS;
-import static android.media.MediaConstants.KEY_PACKAGE_NAME;
-import static android.media.MediaConstants.KEY_PID;
-import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE;
-import static android.media.MediaConstants.KEY_SESSION2LINK;
-import static android.media.MediaConstants.KEY_TOKEN_EXTRAS;
-import static android.media.Session2Command.Result.RESULT_ERROR_UNKNOWN_ERROR;
-import static android.media.Session2Command.Result.RESULT_INFO_SKIPPED;
-import static android.media.Session2Token.TYPE_SESSION;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.media.session.MediaSessionManager;
-import android.media.session.MediaSessionManager.RemoteUserInfo;
-import android.os.BadParcelableException;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Parcel;
-import android.os.Process;
-import android.os.ResultReceiver;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-
-import com.android.modules.utils.build.SdkLevel;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-
-/**
- * This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
- * Library</a> for consistent behavior across all devices.
- * <p>
- * Allows a media app to expose its transport controls and playback information in a process to
- * other processes including the Android framework and other apps.
- */
-public class MediaSession2 implements AutoCloseable {
-    static final String TAG = "MediaSession2";
-    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    // Note: This checks the uniqueness of a session ID only in a single process.
-    // When the framework becomes able to check the uniqueness, this logic should be removed.
-    //@GuardedBy("MediaSession.class")
-    private static final List<String> SESSION_ID_LIST = new ArrayList<>();
-
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final Object mLock = new Object();
-    //@GuardedBy("mLock")
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final Map<Controller2Link, ControllerInfo> mConnectedControllers = new HashMap<>();
-
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final Context mContext;
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final Executor mCallbackExecutor;
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final SessionCallback mCallback;
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final Session2Link mSessionStub;
-
-    private final String mSessionId;
-    private final PendingIntent mSessionActivity;
-    private final Session2Token mSessionToken;
-    private final MediaSessionManager mMediaSessionManager;
-    private final MediaCommunicationManager mCommunicationManager;
-    private final Handler mResultHandler;
-
-    //@GuardedBy("mLock")
-    private boolean mClosed;
-    //@GuardedBy("mLock")
-    private boolean mPlaybackActive;
-    //@GuardedBy("mLock")
-    private ForegroundServiceEventCallback mForegroundServiceEventCallback;
-
-    MediaSession2(@NonNull Context context, @NonNull String id, PendingIntent sessionActivity,
-            @NonNull Executor callbackExecutor, @NonNull SessionCallback callback,
-            @NonNull Bundle tokenExtras) {
-        synchronized (MediaSession2.class) {
-            if (SESSION_ID_LIST.contains(id)) {
-                throw new IllegalStateException("Session ID must be unique. ID=" + id);
-            }
-            SESSION_ID_LIST.add(id);
-        }
-
-        mContext = context;
-        mSessionId = id;
-        mSessionActivity = sessionActivity;
-        mCallbackExecutor = callbackExecutor;
-        mCallback = callback;
-        mSessionStub = new Session2Link(this);
-        mSessionToken = new Session2Token(Process.myUid(), TYPE_SESSION, context.getPackageName(),
-                mSessionStub, tokenExtras);
-        if (SdkLevel.isAtLeastS()) {
-            mCommunicationManager = mContext.getSystemService(MediaCommunicationManager.class);
-            mMediaSessionManager = null;
-        } else {
-            mMediaSessionManager = mContext.getSystemService(MediaSessionManager.class);
-            mCommunicationManager = null;
-        }
-        // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
-        mResultHandler = new Handler(context.getMainLooper());
-        mClosed = false;
-    }
-
-    @Override
-    public void close() {
-        try {
-            List<ControllerInfo> controllerInfos;
-            ForegroundServiceEventCallback callback;
-            synchronized (mLock) {
-                if (mClosed) {
-                    return;
-                }
-                mClosed = true;
-                controllerInfos = getConnectedControllers();
-                mConnectedControllers.clear();
-                callback = mForegroundServiceEventCallback;
-                mForegroundServiceEventCallback = null;
-            }
-            synchronized (MediaSession2.class) {
-                SESSION_ID_LIST.remove(mSessionId);
-            }
-            if (callback != null) {
-                callback.onSessionClosed(this);
-            }
-            for (ControllerInfo info : controllerInfos) {
-                info.notifyDisconnected();
-            }
-        } catch (Exception e) {
-            // Should not be here.
-        }
-    }
-
-    /**
-     * Returns the session ID
-     */
-    @NonNull
-    public String getId() {
-        return mSessionId;
-    }
-
-    /**
-     * Returns the {@link Session2Token} for creating {@link MediaController2}.
-     */
-    @NonNull
-    public Session2Token getToken() {
-        return mSessionToken;
-    }
-
-    /**
-     * Broadcasts a session command to all the connected controllers
-     * <p>
-     * @param command the session command
-     * @param args optional arguments
-     */
-    public void broadcastSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) {
-        if (command == null) {
-            throw new IllegalArgumentException("command shouldn't be null");
-        }
-        List<ControllerInfo> controllerInfos = getConnectedControllers();
-        for (ControllerInfo controller : controllerInfos) {
-            controller.sendSessionCommand(command, args, null);
-        }
-    }
-
-    /**
-     * Sends a session command to a specific controller
-     * <p>
-     * @param controller the controller to get the session command
-     * @param command the session command
-     * @param args optional arguments
-     * @return a token which will be sent together in {@link SessionCallback#onCommandResult}
-     *     when its result is received.
-     */
-    @NonNull
-    public Object sendSessionCommand(@NonNull ControllerInfo controller,
-            @NonNull Session2Command command, @Nullable Bundle args) {
-        if (controller == null) {
-            throw new IllegalArgumentException("controller shouldn't be null");
-        }
-        if (command == null) {
-            throw new IllegalArgumentException("command shouldn't be null");
-        }
-        ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) {
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                controller.receiveCommandResult(this);
-                mCallbackExecutor.execute(() -> {
-                    mCallback.onCommandResult(MediaSession2.this, controller, this,
-                            command, new Session2Command.Result(resultCode, resultData));
-                });
-            }
-        };
-        controller.sendSessionCommand(command, args, resultReceiver);
-        return resultReceiver;
-    }
-
-    /**
-     * Cancels the session command previously sent.
-     *
-     * @param controller the controller to get the session command
-     * @param token the token which is returned from {@link #sendSessionCommand}.
-     */
-    public void cancelSessionCommand(@NonNull ControllerInfo controller, @NonNull Object token) {
-        if (controller == null) {
-            throw new IllegalArgumentException("controller shouldn't be null");
-        }
-        if (token == null) {
-            throw new IllegalArgumentException("token shouldn't be null");
-        }
-        controller.cancelSessionCommand(token);
-    }
-
-    /**
-     * Sets whether the playback is active (i.e. playing something)
-     *
-     * @param playbackActive {@code true} if the playback active, {@code false} otherwise.
-     **/
-    public void setPlaybackActive(boolean playbackActive) {
-        final ForegroundServiceEventCallback serviceCallback;
-        synchronized (mLock) {
-            if (mPlaybackActive == playbackActive) {
-                return;
-            }
-            mPlaybackActive = playbackActive;
-            serviceCallback = mForegroundServiceEventCallback;
-        }
-        if (serviceCallback != null) {
-            serviceCallback.onPlaybackActiveChanged(this, playbackActive);
-        }
-        List<ControllerInfo> controllerInfos = getConnectedControllers();
-        for (ControllerInfo controller : controllerInfos) {
-            controller.notifyPlaybackActiveChanged(playbackActive);
-        }
-    }
-
-    /**
-     * Returns whether the playback is active (i.e. playing something)
-     *
-     * @return {@code true} if the playback active, {@code false} otherwise.
-     */
-    public boolean isPlaybackActive() {
-        synchronized (mLock) {
-            return mPlaybackActive;
-        }
-    }
-
-    /**
-     * Gets the list of the connected controllers
-     *
-     * @return list of the connected controllers.
-     */
-    @NonNull
-    public List<ControllerInfo> getConnectedControllers() {
-        List<ControllerInfo> controllers = new ArrayList<>();
-        synchronized (mLock) {
-            controllers.addAll(mConnectedControllers.values());
-        }
-        return controllers;
-    }
-
-    /**
-     * Returns whether the given bundle includes non-framework Parcelables.
-     */
-    static boolean hasCustomParcelable(@Nullable Bundle bundle) {
-        if (bundle == null) {
-            return false;
-        }
-
-        // Try writing the bundle to parcel, and read it with framework classloader.
-        Parcel parcel = null;
-        try {
-            parcel = Parcel.obtain();
-            parcel.writeBundle(bundle);
-            parcel.setDataPosition(0);
-            Bundle out = parcel.readBundle(null);
-
-            for (String key : out.keySet()) {
-                out.get(key);
-            }
-        } catch (BadParcelableException e) {
-            Log.d(TAG, "Custom parcelable in bundle.", e);
-            return true;
-        } finally {
-            if (parcel != null) {
-                parcel.recycle();
-            }
-        }
-        return false;
-    }
-
-    boolean isClosed() {
-        synchronized (mLock) {
-            return mClosed;
-        }
-    }
-
-    SessionCallback getCallback() {
-        return mCallback;
-    }
-
-    boolean isTrustedForMediaControl(RemoteUserInfo remoteUserInfo) {
-        if (SdkLevel.isAtLeastS()) {
-            return mCommunicationManager.isTrustedForMediaControl(remoteUserInfo);
-        } else {
-            return mMediaSessionManager.isTrustedForMediaControl(remoteUserInfo);
-        }
-    }
-
-    void setForegroundServiceEventCallback(ForegroundServiceEventCallback callback) {
-        synchronized (mLock) {
-            if (mForegroundServiceEventCallback == callback) {
-                return;
-            }
-            if (mForegroundServiceEventCallback != null && callback != null) {
-                throw new IllegalStateException("A session cannot be added to multiple services");
-            }
-            mForegroundServiceEventCallback = callback;
-        }
-    }
-
-    // Called by Session2Link.onConnect and MediaSession2Service.MediaSession2ServiceStub.connect
-    void onConnect(final Controller2Link controller, int callingPid, int callingUid, int seq,
-            Bundle connectionRequest) {
-        if (callingPid == 0) {
-            // The pid here is from Binder.getCallingPid(), which can be 0 for an oneway call from
-            // the remote process. If it's the case, use PID from the connectionRequest.
-            callingPid = connectionRequest.getInt(KEY_PID);
-        }
-        String callingPkg = connectionRequest.getString(KEY_PACKAGE_NAME);
-
-        RemoteUserInfo remoteUserInfo = new RemoteUserInfo(callingPkg, callingPid, callingUid);
-
-        Bundle connectionHints = connectionRequest.getBundle(KEY_CONNECTION_HINTS);
-        if (connectionHints == null) {
-            Log.w(TAG, "connectionHints shouldn't be null.");
-            connectionHints = Bundle.EMPTY;
-        } else if (hasCustomParcelable(connectionHints)) {
-            Log.w(TAG, "connectionHints contain custom parcelable. Ignoring.");
-            connectionHints = Bundle.EMPTY;
-        }
-
-        final ControllerInfo controllerInfo = new ControllerInfo(
-                remoteUserInfo,
-                isTrustedForMediaControl(remoteUserInfo),
-                controller,
-                connectionHints);
-        mCallbackExecutor.execute(() -> {
-            boolean connected = false;
-            try {
-                if (isClosed()) {
-                    return;
-                }
-                controllerInfo.mAllowedCommands =
-                        mCallback.onConnect(MediaSession2.this, 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.
-                if (controllerInfo.mAllowedCommands == null && !controllerInfo.isTrusted()) {
-                    return;
-                }
-                if (controllerInfo.mAllowedCommands == null) {
-                    // For trusted apps, send non-null allowed commands to keep
-                    // connection.
-                    controllerInfo.mAllowedCommands =
-                            new Session2CommandGroup.Builder().build();
-                }
-                if (DEBUG) {
-                    Log.d(TAG, "Accepting connection: " + controllerInfo);
-                }
-                // If connection is accepted, notify the current state to the controller.
-                // It's needed because we cannot call synchronous calls between
-                // session/controller.
-                Bundle connectionResult = new Bundle();
-                connectionResult.putParcelable(KEY_SESSION2LINK, mSessionStub);
-                connectionResult.putParcelable(KEY_ALLOWED_COMMANDS,
-                        controllerInfo.mAllowedCommands);
-                connectionResult.putBoolean(KEY_PLAYBACK_ACTIVE, isPlaybackActive());
-                connectionResult.putBundle(KEY_TOKEN_EXTRAS, mSessionToken.getExtras());
-
-                // Double check if session is still there, because close() can be called in
-                // another thread.
-                if (isClosed()) {
-                    return;
-                }
-                controllerInfo.notifyConnected(connectionResult);
-                synchronized (mLock) {
-                    if (mConnectedControllers.containsKey(controller)) {
-                        Log.w(TAG, "Controller " + controllerInfo + " has sent connection"
-                                + " request multiple times");
-                    }
-                    mConnectedControllers.put(controller, controllerInfo);
-                }
-                mCallback.onPostConnect(MediaSession2.this, controllerInfo);
-                connected = true;
-            } finally {
-                if (!connected || isClosed()) {
-                    if (DEBUG) {
-                        Log.d(TAG, "Rejecting connection or notifying that session is closed"
-                                + ", controllerInfo=" + controllerInfo);
-                    }
-                    synchronized (mLock) {
-                        mConnectedControllers.remove(controller);
-                    }
-                    controllerInfo.notifyDisconnected();
-                }
-            }
-        });
-    }
-
-    // Called by Session2Link.onDisconnect
-    void onDisconnect(@NonNull final Controller2Link controller, int seq) {
-        final ControllerInfo controllerInfo;
-        synchronized (mLock) {
-            controllerInfo = mConnectedControllers.remove(controller);
-        }
-        if (controllerInfo == null) {
-            return;
-        }
-        mCallbackExecutor.execute(() -> {
-            mCallback.onDisconnected(MediaSession2.this, controllerInfo);
-        });
-    }
-
-    // Called by Session2Link.onSessionCommand
-    void onSessionCommand(@NonNull final Controller2Link controller, final int seq,
-            final Session2Command command, final Bundle args,
-            @Nullable ResultReceiver resultReceiver) {
-        if (controller == null) {
-            return;
-        }
-        final ControllerInfo controllerInfo;
-        synchronized (mLock) {
-            controllerInfo = mConnectedControllers.get(controller);
-        }
-        if (controllerInfo == null) {
-            return;
-        }
-
-        // TODO: check allowed commands.
-        synchronized (mLock) {
-            controllerInfo.addRequestedCommandSeqNumber(seq);
-        }
-        mCallbackExecutor.execute(() -> {
-            if (!controllerInfo.removeRequestedCommandSeqNumber(seq)) {
-                if (resultReceiver != null) {
-                    resultReceiver.send(RESULT_INFO_SKIPPED, null);
-                }
-                return;
-            }
-            Session2Command.Result result = mCallback.onSessionCommand(
-                    MediaSession2.this, controllerInfo, command, args);
-            if (resultReceiver != null) {
-                if (result == null) {
-                    resultReceiver.send(RESULT_INFO_SKIPPED, null);
-                } else {
-                    resultReceiver.send(result.getResultCode(), result.getResultData());
-                }
-            }
-        });
-    }
-
-    // Called by Session2Link.onCancelCommand
-    void onCancelCommand(@NonNull final Controller2Link controller, final int seq) {
-        final ControllerInfo controllerInfo;
-        synchronized (mLock) {
-            controllerInfo = mConnectedControllers.get(controller);
-        }
-        if (controllerInfo == null) {
-            return;
-        }
-        controllerInfo.removeRequestedCommandSeqNumber(seq);
-    }
-
-    /**
-     * This API is not generally intended for third party application developers.
-     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
-     * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
-     * Library</a> for consistent behavior across all devices.
-     * <p>
-     * Builder for {@link MediaSession2}.
-     * <p>
-     * Any incoming event from the {@link MediaController2} will be handled on the callback
-     * executor. If it's not set, {@link Context#getMainExecutor()} will be used by default.
-     */
-    public static final class Builder {
-        private Context mContext;
-        private String mId;
-        private PendingIntent mSessionActivity;
-        private Executor mCallbackExecutor;
-        private SessionCallback mCallback;
-        private Bundle mExtras;
-
-        /**
-         * Creates a builder for {@link MediaSession2}.
-         *
-         * @param context Context
-         * @throws IllegalArgumentException if context is {@code null}.
-         */
-        public Builder(@NonNull Context context) {
-            if (context == null) {
-                throw new IllegalArgumentException("context shouldn't be null");
-            }
-            mContext = context;
-        }
-
-        /**
-         * Set an intent for launching UI for this Session. This can be used as a
-         * quick link to an ongoing media screen. The intent should be for an
-         * activity that may be started using {@link Context#startActivity(Intent)}.
-         *
-         * @param pi The intent to launch to show UI for this session.
-         * @return The Builder to allow chaining
-         */
-        @NonNull
-        public Builder setSessionActivity(@Nullable PendingIntent pi) {
-            mSessionActivity = pi;
-            return this;
-        }
-
-        /**
-         * Set ID of the session. If it's not set, an empty string will be used to create a session.
-         * <p>
-         * Use this if and only if your app supports multiple playback at the same time and also
-         * wants to provide external apps to have finer controls of them.
-         *
-         * @param id id of the session. Must be unique per package.
-         * @throws IllegalArgumentException if id is {@code null}.
-         * @return The Builder to allow chaining
-         */
-        @NonNull
-        public Builder setId(@NonNull String id) {
-            if (id == null) {
-                throw new IllegalArgumentException("id shouldn't be null");
-            }
-            mId = id;
-            return this;
-        }
-
-        /**
-         * Set callback for the session and its executor.
-         *
-         * @param executor callback executor
-         * @param callback session callback.
-         * @return The Builder to allow chaining
-         */
-        @NonNull
-        public Builder setSessionCallback(@NonNull Executor executor,
-                @NonNull SessionCallback callback) {
-            mCallbackExecutor = executor;
-            mCallback = callback;
-            return this;
-        }
-
-        /**
-         * Set extras for the session token. If null or not set, {@link Session2Token#getExtras()}
-         * will return an empty {@link Bundle}. An {@link IllegalArgumentException} will be thrown
-         * if the bundle contains any non-framework Parcelable objects.
-         *
-         * @return The Builder to allow chaining
-         * @see Session2Token#getExtras()
-         */
-        @NonNull
-        public Builder setExtras(@NonNull Bundle extras) {
-            if (extras == null) {
-                throw new NullPointerException("extras shouldn't be null");
-            }
-            if (hasCustomParcelable(extras)) {
-                throw new IllegalArgumentException(
-                        "extras shouldn't contain any custom parcelables");
-            }
-            mExtras = new Bundle(extras);
-            return this;
-        }
-
-        /**
-         * Build {@link MediaSession2}.
-         *
-         * @return a new session
-         * @throws IllegalStateException if the session with the same id is already exists for the
-         *      package.
-         */
-        @NonNull
-        public MediaSession2 build() {
-            if (mCallbackExecutor == null) {
-                mCallbackExecutor = mContext.getMainExecutor();
-            }
-            if (mCallback == null) {
-                mCallback = new SessionCallback() {};
-            }
-            if (mId == null) {
-                mId = "";
-            }
-            if (mExtras == null) {
-                mExtras = Bundle.EMPTY;
-            }
-            MediaSession2 session2 = new MediaSession2(mContext, mId, mSessionActivity,
-                    mCallbackExecutor, mCallback, mExtras);
-
-            // Notify framework about the newly create session after the constructor is finished.
-            // Otherwise, framework may access the session before the initialization is finished.
-            try {
-                if (SdkLevel.isAtLeastS()) {
-                    MediaCommunicationManager manager =
-                            mContext.getSystemService(MediaCommunicationManager.class);
-                    manager.notifySession2Created(session2.getToken());
-                } else {
-                    MediaSessionManager manager =
-                            mContext.getSystemService(MediaSessionManager.class);
-                    manager.notifySession2Created(session2.getToken());
-                }
-            } catch (Exception e) {
-                session2.close();
-                throw e;
-            }
-
-            return session2;
-        }
-    }
-
-    /**
-     * This API is not generally intended for third party application developers.
-     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
-     * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
-     * Library</a> for consistent behavior across all devices.
-     * <p>
-     * Information of a controller.
-     */
-    public static final class ControllerInfo {
-        private final RemoteUserInfo mRemoteUserInfo;
-        private final boolean mIsTrusted;
-        private final Controller2Link mControllerBinder;
-        private final Bundle mConnectionHints;
-        private final Object mLock = new Object();
-        //@GuardedBy("mLock")
-        private int mNextSeqNumber;
-        //@GuardedBy("mLock")
-        private ArrayMap<ResultReceiver, Integer> mPendingCommands;
-        //@GuardedBy("mLock")
-        private ArraySet<Integer> mRequestedCommandSeqNumbers;
-
-        @SuppressWarnings("WeakerAccess") /* synthetic access */
-        Session2CommandGroup mAllowedCommands;
-
-        /**
-         * @param remoteUserInfo remote user info
-         * @param trusted {@code true} if trusted, {@code false} otherwise
-         * @param controllerBinder Controller2Link for the connected controller.
-         * @param connectionHints a session-specific argument sent from the controller for the
-         *                        connection. The contents of this bundle may affect the
-         *                        connection result.
-         */
-        ControllerInfo(@NonNull RemoteUserInfo remoteUserInfo, boolean trusted,
-                @Nullable Controller2Link controllerBinder, @NonNull Bundle connectionHints) {
-            mRemoteUserInfo = remoteUserInfo;
-            mIsTrusted = trusted;
-            mControllerBinder = controllerBinder;
-            mConnectionHints = connectionHints;
-            mPendingCommands = new ArrayMap<>();
-            mRequestedCommandSeqNumbers = new ArraySet<>();
-        }
-
-        /**
-         * @return remote user info of the controller.
-         */
-        @NonNull
-        public RemoteUserInfo getRemoteUserInfo() {
-            return mRemoteUserInfo;
-        }
-
-        /**
-         * @return package name of the controller.
-         */
-        @NonNull
-        public String getPackageName() {
-            return mRemoteUserInfo.getPackageName();
-        }
-
-        /**
-         * @return uid of the controller. Can be a negative value if the uid cannot be obtained.
-         */
-        public int getUid() {
-            return mRemoteUserInfo.getUid();
-        }
-
-        /**
-         * @return connection hints sent from controller.
-         */
-        @NonNull
-        public Bundle getConnectionHints() {
-            return new Bundle(mConnectionHints);
-        }
-
-        /**
-         * Return if the controller has granted {@code android.permission.MEDIA_CONTENT_CONTROL} or
-         * has a enabled notification listener so can be trusted to accept connection and incoming
-         * command request.
-         *
-         * @return {@code true} if the controller is trusted.
-         * @hide
-         */
-        public boolean isTrusted() {
-            return mIsTrusted;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(mControllerBinder, mRemoteUserInfo);
-        }
-
-        @Override
-        public boolean equals(@Nullable Object obj) {
-            if (!(obj instanceof ControllerInfo)) return false;
-            if (this == obj) return true;
-
-            ControllerInfo other = (ControllerInfo) obj;
-            if (mControllerBinder != null || other.mControllerBinder != null) {
-                return Objects.equals(mControllerBinder, other.mControllerBinder);
-            }
-            return mRemoteUserInfo.equals(other.mRemoteUserInfo);
-        }
-
-        @Override
-        @NonNull
-        public String toString() {
-            return "ControllerInfo {pkg=" + mRemoteUserInfo.getPackageName() + ", uid="
-                    + mRemoteUserInfo.getUid() + ", allowedCommands=" + mAllowedCommands + "})";
-        }
-
-        void notifyConnected(Bundle connectionResult) {
-            if (mControllerBinder == null) return;
-
-            try {
-                mControllerBinder.notifyConnected(getNextSeqNumber(), connectionResult);
-            } catch (RuntimeException e) {
-                // Controller may be died prematurely.
-            }
-        }
-
-        void notifyDisconnected() {
-            if (mControllerBinder == null) return;
-
-            try {
-                mControllerBinder.notifyDisconnected(getNextSeqNumber());
-            } catch (RuntimeException e) {
-                // Controller may be died prematurely.
-            }
-        }
-
-        void notifyPlaybackActiveChanged(boolean playbackActive) {
-            if (mControllerBinder == null) return;
-
-            try {
-                mControllerBinder.notifyPlaybackActiveChanged(getNextSeqNumber(), playbackActive);
-            } catch (RuntimeException e) {
-                // Controller may be died prematurely.
-            }
-        }
-
-        void sendSessionCommand(Session2Command command, Bundle args,
-                ResultReceiver resultReceiver) {
-            if (mControllerBinder == null) return;
-
-            try {
-                int seq = getNextSeqNumber();
-                synchronized (mLock) {
-                    mPendingCommands.put(resultReceiver, seq);
-                }
-                mControllerBinder.sendSessionCommand(seq, command, args, resultReceiver);
-            } catch (RuntimeException e) {
-                // Controller may be died prematurely.
-                synchronized (mLock) {
-                    mPendingCommands.remove(resultReceiver);
-                }
-                resultReceiver.send(RESULT_ERROR_UNKNOWN_ERROR, null);
-            }
-        }
-
-        void cancelSessionCommand(@NonNull Object token) {
-            if (mControllerBinder == null) return;
-            Integer seq;
-            synchronized (mLock) {
-                seq = mPendingCommands.remove(token);
-            }
-            if (seq != null) {
-                mControllerBinder.cancelSessionCommand(seq);
-            }
-        }
-
-        void receiveCommandResult(ResultReceiver resultReceiver) {
-            synchronized (mLock) {
-                mPendingCommands.remove(resultReceiver);
-            }
-        }
-
-        void addRequestedCommandSeqNumber(int seq) {
-            synchronized (mLock) {
-                mRequestedCommandSeqNumbers.add(seq);
-            }
-        }
-
-        boolean removeRequestedCommandSeqNumber(int seq) {
-            synchronized (mLock) {
-                return mRequestedCommandSeqNumbers.remove(seq);
-            }
-        }
-
-        private int getNextSeqNumber() {
-            synchronized (mLock) {
-                return mNextSeqNumber++;
-            }
-        }
-    }
-
-    /**
-     * This API is not generally intended for third party application developers.
-     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
-     * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
-     * Library</a> for consistent behavior across all devices.
-     * <p>
-     * Callback to be called for all incoming commands from {@link MediaController2}s.
-     */
-    public abstract static class SessionCallback {
-        /**
-         * Called when a controller is created for this session. Return allowed commands for
-         * controller. By default it returns {@code null}.
-         * <p>
-         * You can reject the connection by returning {@code null}. In that case, controller
-         * receives {@link MediaController2.ControllerCallback#onDisconnected(MediaController2)}
-         * and cannot be used.
-         * <p>
-         * The controller hasn't connected yet in this method, so calls to the controller
-         * (e.g. {@link #sendSessionCommand}) would be ignored. Override {@link #onPostConnect} for
-         * the custom initialization for the controller instead.
-         *
-         * @param session the session for this event
-         * @param controller controller information.
-         * @return allowed commands. Can be {@code null} to reject connection.
-         */
-        @Nullable
-        public Session2CommandGroup onConnect(@NonNull MediaSession2 session,
-                @NonNull ControllerInfo controller) {
-            return null;
-        }
-
-        /**
-         * Called immediately after a controller is connected. This is a convenient method to add
-         * custom initialization between the session and a controller.
-         * <p>
-         * Note that calls to the controller (e.g. {@link #sendSessionCommand}) work here but don't
-         * work in {@link #onConnect} because the controller hasn't connected yet in
-         * {@link #onConnect}.
-         *
-         * @param session the session for this event
-         * @param controller controller information.
-         */
-        public void onPostConnect(@NonNull MediaSession2 session,
-                @NonNull ControllerInfo controller) {
-        }
-
-        /**
-         * Called when a controller is disconnected
-         *
-         * @param session the session for this event
-         * @param controller controller information
-         */
-        public void onDisconnected(@NonNull MediaSession2 session,
-                @NonNull ControllerInfo controller) {}
-
-        /**
-         * Called when a controller sent a session command.
-         *
-         * @param session the session for this event
-         * @param controller controller information
-         * @param command the session command
-         * @param args optional arguments
-         * @return the result for the session command. If {@code null}, RESULT_INFO_SKIPPED
-         *         will be sent to the session.
-         */
-        @Nullable
-        public Session2Command.Result onSessionCommand(@NonNull MediaSession2 session,
-                @NonNull ControllerInfo controller, @NonNull Session2Command command,
-                @Nullable Bundle args) {
-            return null;
-        }
-
-        /**
-         * Called when the command sent to the controller is finished.
-         *
-         * @param session the session for this event
-         * @param controller controller information
-         * @param token the token got from {@link MediaSession2#sendSessionCommand}
-         * @param command the session command
-         * @param result the result of the session command
-         */
-        public void onCommandResult(@NonNull MediaSession2 session,
-                @NonNull ControllerInfo controller, @NonNull Object token,
-                @NonNull Session2Command command, @NonNull Session2Command.Result result) {}
-    }
-
-    abstract static class ForegroundServiceEventCallback {
-        public void onPlaybackActiveChanged(MediaSession2 session, boolean playbackActive) {}
-        public void onSessionClosed(MediaSession2 session) {}
-    }
-}
diff --git a/apex/media/framework/java/android/media/MediaSession2Service.java b/apex/media/framework/java/android/media/MediaSession2Service.java
deleted file mode 100644
index 9f80c43..0000000
--- a/apex/media/framework/java/android/media/MediaSession2Service.java
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * Copyright 2019 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 android.media;
-
-import static android.media.MediaConstants.KEY_CONNECTION_HINTS;
-import static android.media.MediaConstants.KEY_PACKAGE_NAME;
-import static android.media.MediaConstants.KEY_PID;
-
-import android.annotation.CallSuper;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.media.MediaSession2.ControllerInfo;
-import android.media.session.MediaSessionManager;
-import android.media.session.MediaSessionManager.RemoteUserInfo;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
- * Library</a> for consistent behavior across all devices.
- * <p>
- * Service containing {@link MediaSession2}.
- */
-public abstract class MediaSession2Service extends Service {
-    /**
-     * The {@link Intent} that must be declared as handled by the service.
-     */
-    public static final String SERVICE_INTERFACE = "android.media.MediaSession2Service";
-
-    private static final String TAG = "MediaSession2Service";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    private final MediaSession2.ForegroundServiceEventCallback mForegroundServiceEventCallback =
-            new MediaSession2.ForegroundServiceEventCallback() {
-                @Override
-                public void onPlaybackActiveChanged(MediaSession2 session, boolean playbackActive) {
-                    MediaSession2Service.this.onPlaybackActiveChanged(session, playbackActive);
-                }
-
-                @Override
-                public void onSessionClosed(MediaSession2 session) {
-                    removeSession(session);
-                }
-            };
-
-    private final Object mLock = new Object();
-    //@GuardedBy("mLock")
-    private NotificationManager mNotificationManager;
-    //@GuardedBy("mLock")
-    private MediaSessionManager mMediaSessionManager;
-    //@GuardedBy("mLock")
-    private Intent mStartSelfIntent;
-    //@GuardedBy("mLock")
-    private Map<String, MediaSession2> mSessions = new ArrayMap<>();
-    //@GuardedBy("mLock")
-    private Map<MediaSession2, MediaNotification> mNotifications = new ArrayMap<>();
-    //@GuardedBy("mLock")
-    private MediaSession2ServiceStub mStub;
-
-    /**
-     * Called by the system when the service is first created. Do not call this method directly.
-     * <p>
-     * Override this method if you need your own initialization. Derived classes MUST call through
-     * to the super class's implementation of this method.
-     */
-    @CallSuper
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        synchronized (mLock) {
-            mStub = new MediaSession2ServiceStub(this);
-            mStartSelfIntent = new Intent(this, this.getClass());
-            mNotificationManager =
-                    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
-            mMediaSessionManager =
-                    (MediaSessionManager) getSystemService(Context.MEDIA_SESSION_SERVICE);
-        }
-    }
-
-    @CallSuper
-    @Override
-    @Nullable
-    public IBinder onBind(@NonNull Intent intent) {
-        if (SERVICE_INTERFACE.equals(intent.getAction())) {
-            synchronized (mLock) {
-                return mStub;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Called by the system to notify that it is no longer used and is being removed. Do not call
-     * this method directly.
-     * <p>
-     * Override this method if you need your own clean up. Derived classes MUST call through
-     * to the super class's implementation of this method.
-     */
-    @CallSuper
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        synchronized (mLock) {
-            List<MediaSession2> sessions = getSessions();
-            for (MediaSession2 session : sessions) {
-                removeSession(session);
-            }
-            mSessions.clear();
-            mNotifications.clear();
-        }
-        mStub.close();
-    }
-
-    /**
-     * Called when a {@link MediaController2} is created with the this service's
-     * {@link Session2Token}. Return the session for telling the controller which session to
-     * connect. Return {@code null} to reject the connection from this controller.
-     * <p>
-     * Session returned here will be added to this service automatically. You don't need to call
-     * {@link #addSession(MediaSession2)} for that.
-     * <p>
-     * This method is always called on the main thread.
-     *
-     * @param controllerInfo information of the controller which is trying to connect.
-     * @return a {@link MediaSession2} instance for the controller to connect to, or {@code null}
-     *         to reject connection
-     * @see MediaSession2.Builder
-     * @see #getSessions()
-     */
-    @Nullable
-    public abstract MediaSession2 onGetSession(@NonNull ControllerInfo controllerInfo);
-
-    /**
-     * Called to update the media notification when the playback state changes.
-     * <p>
-     * If playback is active and a notification is returned, the service uses it to become a
-     * foreground service. If playback is not active then the notification is still posted, but the
-     * service does not become a foreground service.
-     * <p>
-     * Apps must request the {@link android.Manifest.permission#FOREGROUND_SERVICE} permission
-     * in order to use this API. For apps targeting {@link android.os.Build.VERSION_CODES#TIRAMISU}
-     * or later, notifications will only be posted if the app has also been granted the
-     * {@link android.Manifest.permission#POST_NOTIFICATIONS} permission.
-     *
-     * @param session the session for which an updated media notification is required.
-     * @return the {@link MediaNotification}. Can be {@code null}.
-     */
-    @Nullable
-    public abstract MediaNotification onUpdateNotification(@NonNull MediaSession2 session);
-
-    /**
-     * Adds a session to this service.
-     * <p>
-     * Added session will be removed automatically when it's closed, or removed when
-     * {@link #removeSession} is called.
-     *
-     * @param session a session to be added.
-     * @see #removeSession(MediaSession2)
-     */
-    public final void addSession(@NonNull MediaSession2 session) {
-        if (session == null) {
-            throw new IllegalArgumentException("session shouldn't be null");
-        }
-        if (session.isClosed()) {
-            throw new IllegalArgumentException("session is already closed");
-        }
-        synchronized (mLock) {
-            MediaSession2 previousSession = mSessions.get(session.getId());
-            if (previousSession != null) {
-                if (previousSession != session) {
-                    Log.w(TAG, "Session ID should be unique, ID=" + session.getId()
-                            + ", previous=" + previousSession + ", session=" + session);
-                }
-                return;
-            }
-            mSessions.put(session.getId(), session);
-            session.setForegroundServiceEventCallback(mForegroundServiceEventCallback);
-        }
-    }
-
-    /**
-     * Removes a session from this service.
-     *
-     * @param session a session to be removed.
-     * @see #addSession(MediaSession2)
-     */
-    public final void removeSession(@NonNull MediaSession2 session) {
-        if (session == null) {
-            throw new IllegalArgumentException("session shouldn't be null");
-        }
-        MediaNotification notification;
-        synchronized (mLock) {
-            if (mSessions.get(session.getId()) != session) {
-                // Session isn't added or removed already.
-                return;
-            }
-            mSessions.remove(session.getId());
-            notification = mNotifications.remove(session);
-        }
-        session.setForegroundServiceEventCallback(null);
-        if (notification != null) {
-            mNotificationManager.cancel(notification.getNotificationId());
-        }
-        if (getSessions().isEmpty()) {
-            stopForeground(false);
-        }
-    }
-
-    /**
-     * Gets the list of {@link MediaSession2}s that you've added to this service.
-     *
-     * @return sessions
-     */
-    public final @NonNull List<MediaSession2> getSessions() {
-        List<MediaSession2> list = new ArrayList<>();
-        synchronized (mLock) {
-            list.addAll(mSessions.values());
-        }
-        return list;
-    }
-
-    /**
-     * Returns the {@link MediaSessionManager}.
-     */
-    @NonNull
-    MediaSessionManager getMediaSessionManager() {
-        synchronized (mLock) {
-            return mMediaSessionManager;
-        }
-    }
-
-    /**
-     * Called by registered {@link MediaSession2.ForegroundServiceEventCallback}
-     *
-     * @param session session with change
-     * @param playbackActive {@code true} if playback is active.
-     */
-    void onPlaybackActiveChanged(MediaSession2 session, boolean playbackActive) {
-        MediaNotification mediaNotification = onUpdateNotification(session);
-        if (mediaNotification == null) {
-            // The service implementation doesn't want to use the automatic start/stopForeground
-            // feature.
-            return;
-        }
-        synchronized (mLock) {
-            mNotifications.put(session, mediaNotification);
-        }
-        int id = mediaNotification.getNotificationId();
-        Notification notification = mediaNotification.getNotification();
-        if (!playbackActive) {
-            mNotificationManager.notify(id, notification);
-            return;
-        }
-        // playbackActive == true
-        startForegroundService(mStartSelfIntent);
-        startForeground(id, notification);
-    }
-
-    /**
-     * This API is not generally intended for third party application developers.
-     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
-     * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
-     * Library</a> for consistent behavior across all devices.
-     * <p>
-     * Returned by {@link #onUpdateNotification(MediaSession2)} for making session service
-     * foreground service to keep playback running in the background. It's highly recommended to
-     * show media style notification here.
-     */
-    public static class MediaNotification {
-        private final int mNotificationId;
-        private final Notification mNotification;
-
-        /**
-         * Default constructor
-         *
-         * @param notificationId notification id to be used for
-         *        {@link NotificationManager#notify(int, Notification)}.
-         * @param notification a notification to make session service run in the foreground. Media
-         *        style notification is recommended here.
-         */
-        public MediaNotification(int notificationId, @NonNull Notification notification) {
-            if (notification == null) {
-                throw new IllegalArgumentException("notification shouldn't be null");
-            }
-            mNotificationId = notificationId;
-            mNotification = notification;
-        }
-
-        /**
-         * Gets the id of the notification.
-         *
-         * @return the notification id
-         */
-        public int getNotificationId() {
-            return mNotificationId;
-        }
-
-        /**
-         * Gets the notification.
-         *
-         * @return the notification
-         */
-        @NonNull
-        public Notification getNotification() {
-            return mNotification;
-        }
-    }
-
-    private static final class MediaSession2ServiceStub extends IMediaSession2Service.Stub
-            implements AutoCloseable {
-        final WeakReference<MediaSession2Service> mService;
-        final Handler mHandler;
-
-        MediaSession2ServiceStub(MediaSession2Service service) {
-            mService = new WeakReference<>(service);
-            mHandler = new Handler(service.getMainLooper());
-        }
-
-        @Override
-        public void connect(Controller2Link caller, int seq, Bundle connectionRequest) {
-            if (mService.get() == null) {
-                if (DEBUG) {
-                    Log.d(TAG, "Service is already destroyed");
-                }
-                return;
-            }
-            if (caller == null || connectionRequest == null) {
-                if (DEBUG) {
-                    Log.d(TAG, "Ignoring calls with illegal arguments, caller=" + caller
-                            + ", connectionRequest=" + connectionRequest);
-                }
-                return;
-            }
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mHandler.post(() -> {
-                    boolean shouldNotifyDisconnected = true;
-                    try {
-                        final MediaSession2Service service = mService.get();
-                        if (service == null) {
-                            if (DEBUG) {
-                                Log.d(TAG, "Service isn't available");
-                            }
-                            return;
-                        }
-
-                        String callingPkg = connectionRequest.getString(KEY_PACKAGE_NAME);
-                        // The Binder.getCallingPid() can be 0 for an oneway call from the
-                        // remote process. If it's the case, use PID from the connectionRequest.
-                        RemoteUserInfo remoteUserInfo = new RemoteUserInfo(
-                                callingPkg,
-                                pid == 0 ? connectionRequest.getInt(KEY_PID) : pid,
-                                uid);
-
-                        Bundle connectionHints = connectionRequest.getBundle(KEY_CONNECTION_HINTS);
-                        if (connectionHints == null) {
-                            Log.w(TAG, "connectionHints shouldn't be null.");
-                            connectionHints = Bundle.EMPTY;
-                        } else if (MediaSession2.hasCustomParcelable(connectionHints)) {
-                            Log.w(TAG, "connectionHints contain custom parcelable. Ignoring.");
-                            connectionHints = Bundle.EMPTY;
-                        }
-
-                        final ControllerInfo controllerInfo = new ControllerInfo(
-                                remoteUserInfo,
-                                service.getMediaSessionManager()
-                                        .isTrustedForMediaControl(remoteUserInfo),
-                                caller,
-                                connectionHints);
-
-                        if (DEBUG) {
-                            Log.d(TAG, "Handling incoming connection request from the"
-                                    + " controller=" + controllerInfo);
-                        }
-
-                        final MediaSession2 session;
-                        session = service.onGetSession(controllerInfo);
-
-                        if (session == null) {
-                            if (DEBUG) {
-                                Log.d(TAG, "Rejecting incoming connection request from the"
-                                        + " controller=" + controllerInfo);
-                            }
-                            // Note: Trusted controllers also can be rejected according to the
-                            // service implementation.
-                            return;
-                        }
-                        service.addSession(session);
-                        shouldNotifyDisconnected = false;
-                        session.onConnect(caller, pid, uid, seq, connectionRequest);
-                    } catch (Exception e) {
-                        // Don't propagate exception in service to the controller.
-                        Log.w(TAG, "Failed to add a session to session service", e);
-                    } finally {
-                        // Trick to call onDisconnected() in one place.
-                        if (shouldNotifyDisconnected) {
-                            if (DEBUG) {
-                                Log.d(TAG, "Notifying the controller of its disconnection");
-                            }
-                            try {
-                                caller.notifyDisconnected(0);
-                            } catch (RuntimeException e) {
-                                // Controller may be died prematurely.
-                                // Not an issue because we'll ignore it anyway.
-                            }
-                        }
-                    }
-                });
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void close() {
-            mHandler.removeCallbacksAndMessages(null);
-            mService.clear();
-        }
-    }
-}
diff --git a/apex/media/framework/java/android/media/MediaTranscodingManager.java b/apex/media/framework/java/android/media/MediaTranscodingManager.java
deleted file mode 100644
index aff3204..0000000
--- a/apex/media/framework/java/android/media/MediaTranscodingManager.java
+++ /dev/null
@@ -1,1749 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.media;
-
-import android.annotation.CallbackExecutor;
-import android.annotation.IntDef;
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.net.Uri;
-import android.os.Build;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.system.Os;
-import android.util.Log;
-
-import androidx.annotation.RequiresApi;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.modules.annotation.MinSdk;
-import com.android.modules.utils.build.SdkLevel;
-
-import java.io.FileNotFoundException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-/**
- Android 12 introduces Compatible media transcoding feature.  See
- <a href="https://developer.android.com/about/versions/12/features#compatible_media_transcoding">
- Compatible media transcoding</a>. MediaTranscodingManager provides an interface to the system's media
- transcoding service and can be used to transcode media files, e.g. transcoding a video from HEVC to
- AVC.
-
- <h3>Transcoding Types</h3>
- <h4>Video Transcoding</h4>
- When transcoding a video file, the video track will be transcoded based on the desired track format
- and the audio track will be pass through without any modification.
- <p class=note>
- Note that currently only support transcoding video file in mp4 format and with single video track.
-
- <h3>Transcoding Request</h3>
- <p>
- To transcode a media file, first create a {@link TranscodingRequest} through its builder class
- {@link VideoTranscodingRequest.Builder}. Transcode requests are then enqueue to the manager through
- {@link MediaTranscodingManager#enqueueRequest(
-         TranscodingRequest, Executor, OnTranscodingFinishedListener)}
- TranscodeRequest are processed based on client process's priority and request priority. When a
- transcode operation is completed the caller is notified via its
- {@link OnTranscodingFinishedListener}.
- In the meantime the caller may use the returned TranscodingSession object to cancel or check the
- status of a specific transcode operation.
- <p>
- Here is an example where <code>Builder</code> is used to specify all parameters
-
- <pre class=prettyprint>
- VideoTranscodingRequest request =
-    new VideoTranscodingRequest.Builder(srcUri, dstUri, videoFormat).build();
- }</pre>
- @hide
- */
-@MinSdk(Build.VERSION_CODES.S)
-@RequiresApi(Build.VERSION_CODES.S)
-@SystemApi
-public final class MediaTranscodingManager {
-    private static final String TAG = "MediaTranscodingManager";
-
-    /** Maximum number of retry to connect to the service. */
-    private static final int CONNECT_SERVICE_RETRY_COUNT = 100;
-
-    /** Interval between trying to reconnect to the service. */
-    private static final int INTERVAL_CONNECT_SERVICE_RETRY_MS = 40;
-
-    /** Default bpp(bits-per-pixel) to use for calculating default bitrate. */
-    private static final float BPP = 0.25f;
-
-    /**
-     * Listener that gets notified when a transcoding operation has finished.
-     * This listener gets notified regardless of how the operation finished. It is up to the
-     * listener implementation to check the result and take appropriate action.
-     */
-    @FunctionalInterface
-    public interface OnTranscodingFinishedListener {
-        /**
-         * Called when the transcoding operation has finished. The receiver may use the
-         * TranscodingSession to check the result, i.e. whether the operation succeeded, was
-         * canceled or if an error occurred.
-         *
-         * @param session The TranscodingSession instance for the finished transcoding operation.
-         */
-        void onTranscodingFinished(@NonNull TranscodingSession session);
-    }
-
-    private final Context mContext;
-    private ContentResolver mContentResolver;
-    private final String mPackageName;
-    private final int mPid;
-    private final int mUid;
-    private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
-    private final HashMap<Integer, TranscodingSession> mPendingTranscodingSessions = new HashMap();
-    private final Object mLock = new Object();
-    @GuardedBy("mLock")
-    @NonNull private ITranscodingClient mTranscodingClient = null;
-    private static MediaTranscodingManager sMediaTranscodingManager;
-
-    private void handleTranscodingFinished(int sessionId, TranscodingResultParcel result) {
-        synchronized (mPendingTranscodingSessions) {
-            // Gets the session associated with the sessionId and removes it from
-            // mPendingTranscodingSessions.
-            final TranscodingSession session = mPendingTranscodingSessions.remove(sessionId);
-
-            if (session == null) {
-                // This should not happen in reality.
-                Log.e(TAG, "Session " + sessionId + " is not in Pendingsessions");
-                return;
-            }
-
-            // Updates the session status and result.
-            session.updateStatusAndResult(TranscodingSession.STATUS_FINISHED,
-                    TranscodingSession.RESULT_SUCCESS,
-                    TranscodingSession.ERROR_NONE);
-
-            // Notifies client the session is done.
-            if (session.mListener != null && session.mListenerExecutor != null) {
-                session.mListenerExecutor.execute(
-                        () -> session.mListener.onTranscodingFinished(session));
-            }
-        }
-    }
-
-    private void handleTranscodingFailed(int sessionId, int errorCode) {
-        synchronized (mPendingTranscodingSessions) {
-            // Gets the session associated with the sessionId and removes it from
-            // mPendingTranscodingSessions.
-            final TranscodingSession session = mPendingTranscodingSessions.remove(sessionId);
-
-            if (session == null) {
-                // This should not happen in reality.
-                Log.e(TAG, "Session " + sessionId + " is not in Pendingsessions");
-                return;
-            }
-
-            // Updates the session status and result.
-            session.updateStatusAndResult(TranscodingSession.STATUS_FINISHED,
-                    TranscodingSession.RESULT_ERROR, errorCode);
-
-            // Notifies client the session failed.
-            if (session.mListener != null && session.mListenerExecutor != null) {
-                session.mListenerExecutor.execute(
-                        () -> session.mListener.onTranscodingFinished(session));
-            }
-        }
-    }
-
-    private void handleTranscodingProgressUpdate(int sessionId, int newProgress) {
-        synchronized (mPendingTranscodingSessions) {
-            // Gets the session associated with the sessionId.
-            final TranscodingSession session = mPendingTranscodingSessions.get(sessionId);
-
-            if (session == null) {
-                // This should not happen in reality.
-                Log.e(TAG, "Session " + sessionId + " is not in Pendingsessions");
-                return;
-            }
-
-            // Updates the session progress.
-            session.updateProgress(newProgress);
-
-            // Notifies client the progress update.
-            if (session.mProgressUpdateExecutor != null
-                    && session.mProgressUpdateListener != null) {
-                session.mProgressUpdateExecutor.execute(
-                        () -> session.mProgressUpdateListener.onProgressUpdate(session,
-                                newProgress));
-            }
-        }
-    }
-
-    private IMediaTranscodingService getService(boolean retry) {
-        // Do not try to get the service on pre-S. The service is lazy-start and getting the
-        // service could block.
-        if (!SdkLevel.isAtLeastS()) {
-            return null;
-        }
-
-        int retryCount = !retry ? 1 :  CONNECT_SERVICE_RETRY_COUNT;
-        Log.i(TAG, "get service with retry " + retryCount);
-        for (int count = 1;  count <= retryCount; count++) {
-            Log.d(TAG, "Trying to connect to service. Try count: " + count);
-            IMediaTranscodingService service = IMediaTranscodingService.Stub.asInterface(
-                    MediaFrameworkInitializer
-                    .getMediaServiceManager()
-                    .getMediaTranscodingServiceRegisterer()
-                    .get());
-            if (service != null) {
-                return service;
-            }
-            try {
-                // Sleep a bit before retry.
-                Thread.sleep(INTERVAL_CONNECT_SERVICE_RETRY_MS);
-            } catch (InterruptedException ie) {
-                /* ignore */
-            }
-        }
-        Log.w(TAG, "Failed to get service");
-        return null;
-    }
-
-    /*
-     * Handle client binder died event.
-     * Upon receiving a binder died event of the client, we will do the following:
-     * 1) For the session that is running, notify the client that the session is failed with
-     *    error code,  so client could choose to retry the session or not.
-     *    TODO(hkuang): Add a new error code to signal service died error.
-     * 2) For the sessions that is still pending or paused, we will resubmit the session
-     *    once we successfully reconnect to the service and register a new client.
-     * 3) When trying to connect to the service and register a new client. The service may need time
-     *    to reboot or never boot up again. So we will retry for a number of times. If we still
-     *    could not connect, we will notify client session failure for the pending and paused
-     *    sessions.
-     */
-    private void onClientDied() {
-        synchronized (mLock) {
-            mTranscodingClient = null;
-        }
-
-        // Delegates the session notification and retry to the executor as it may take some time.
-        mExecutor.execute(() -> {
-            // List to track the sessions that we want to retry.
-            List<TranscodingSession> retrySessions = new ArrayList<TranscodingSession>();
-
-            // First notify the client of session failure for all the running sessions.
-            synchronized (mPendingTranscodingSessions) {
-                for (Map.Entry<Integer, TranscodingSession> entry :
-                        mPendingTranscodingSessions.entrySet()) {
-                    TranscodingSession session = entry.getValue();
-
-                    if (session.getStatus() == TranscodingSession.STATUS_RUNNING) {
-                        session.updateStatusAndResult(TranscodingSession.STATUS_FINISHED,
-                                TranscodingSession.RESULT_ERROR,
-                                TranscodingSession.ERROR_SERVICE_DIED);
-
-                        // Remove the session from pending sessions.
-                        mPendingTranscodingSessions.remove(entry.getKey());
-
-                        if (session.mListener != null && session.mListenerExecutor != null) {
-                            Log.i(TAG, "Notify client session failed");
-                            session.mListenerExecutor.execute(
-                                    () -> session.mListener.onTranscodingFinished(session));
-                        }
-                    } else if (session.getStatus() == TranscodingSession.STATUS_PENDING
-                            || session.getStatus() == TranscodingSession.STATUS_PAUSED) {
-                        // Add the session to retrySessions to handle them later.
-                        retrySessions.add(session);
-                    }
-                }
-            }
-
-            // Try to register with the service once it boots up.
-            IMediaTranscodingService service = getService(true /*retry*/);
-            boolean haveTranscodingClient = false;
-            if (service != null) {
-                synchronized (mLock) {
-                    mTranscodingClient = registerClient(service);
-                    if (mTranscodingClient != null) {
-                        haveTranscodingClient = true;
-                    }
-                }
-            }
-
-            for (TranscodingSession session : retrySessions) {
-                // Notify the session failure if we fails to connect to the service or fail
-                // to retry the session.
-                if (!haveTranscodingClient) {
-                    // TODO(hkuang): Return correct error code to the client.
-                    handleTranscodingFailed(session.getSessionId(), 0 /*unused */);
-                }
-
-                try {
-                    // Do not set hasRetried for retry initiated by MediaTranscodingManager.
-                    session.retryInternal(false /*setHasRetried*/);
-                } catch (Exception re) {
-                    // TODO(hkuang): Return correct error code to the client.
-                    handleTranscodingFailed(session.getSessionId(), 0 /*unused */);
-                }
-            }
-        });
-    }
-
-    private void updateStatus(int sessionId, int status) {
-        synchronized (mPendingTranscodingSessions) {
-            final TranscodingSession session = mPendingTranscodingSessions.get(sessionId);
-
-            if (session == null) {
-                // This should not happen in reality.
-                Log.e(TAG, "Session " + sessionId + " is not in Pendingsessions");
-                return;
-            }
-
-            // Updates the session status.
-            session.updateStatus(status);
-        }
-    }
-
-    // Just forwards all the events to the event handler.
-    private ITranscodingClientCallback mTranscodingClientCallback =
-            new ITranscodingClientCallback.Stub() {
-                // TODO(hkuang): Add more unit test to test difference file open mode.
-                @Override
-                public ParcelFileDescriptor openFileDescriptor(String fileUri, String mode)
-                        throws RemoteException {
-                    if (!mode.equals("r") && !mode.equals("w") && !mode.equals("rw")) {
-                        Log.e(TAG, "Unsupport mode: " + mode);
-                        return null;
-                    }
-
-                    Uri uri = Uri.parse(fileUri);
-                    try {
-                        AssetFileDescriptor afd = mContentResolver.openAssetFileDescriptor(uri,
-                                mode);
-                        if (afd != null) {
-                            return afd.getParcelFileDescriptor();
-                        }
-                    } catch (FileNotFoundException e) {
-                        Log.w(TAG, "Cannot find content uri: " + uri, e);
-                    } catch (SecurityException e) {
-                        Log.w(TAG, "Cannot open content uri: " + uri, e);
-                    } catch (Exception e) {
-                        Log.w(TAG, "Unknown content uri: " + uri, e);
-                    }
-                    return null;
-                }
-
-                @Override
-                public void onTranscodingStarted(int sessionId) throws RemoteException {
-                    updateStatus(sessionId, TranscodingSession.STATUS_RUNNING);
-                }
-
-                @Override
-                public void onTranscodingPaused(int sessionId) throws RemoteException {
-                    updateStatus(sessionId, TranscodingSession.STATUS_PAUSED);
-                }
-
-                @Override
-                public void onTranscodingResumed(int sessionId) throws RemoteException {
-                    updateStatus(sessionId, TranscodingSession.STATUS_RUNNING);
-                }
-
-                @Override
-                public void onTranscodingFinished(int sessionId, TranscodingResultParcel result)
-                        throws RemoteException {
-                    handleTranscodingFinished(sessionId, result);
-                }
-
-                @Override
-                public void onTranscodingFailed(int sessionId, int errorCode)
-                        throws RemoteException {
-                    handleTranscodingFailed(sessionId, errorCode);
-                }
-
-                @Override
-                public void onAwaitNumberOfSessionsChanged(int sessionId, int oldAwaitNumber,
-                        int newAwaitNumber) throws RemoteException {
-                    //TODO(hkuang): Implement this.
-                }
-
-                @Override
-                public void onProgressUpdate(int sessionId, int newProgress)
-                        throws RemoteException {
-                    handleTranscodingProgressUpdate(sessionId, newProgress);
-                }
-            };
-
-    private ITranscodingClient registerClient(IMediaTranscodingService service) {
-        synchronized (mLock) {
-            try {
-                // Registers the client with MediaTranscoding service.
-                mTranscodingClient = service.registerClient(
-                        mTranscodingClientCallback,
-                        mPackageName,
-                        mPackageName);
-
-                if (mTranscodingClient != null) {
-                    mTranscodingClient.asBinder().linkToDeath(() -> onClientDied(), /* flags */ 0);
-                }
-            } catch (Exception ex) {
-                Log.e(TAG, "Failed to register new client due to exception " + ex);
-                mTranscodingClient = null;
-            }
-        }
-        return mTranscodingClient;
-    }
-
-    /**
-     * @hide
-     */
-    public MediaTranscodingManager(@NonNull Context context) {
-        mContext = context;
-        mContentResolver = mContext.getContentResolver();
-        mPackageName = mContext.getPackageName();
-        mUid = Os.getuid();
-        mPid = Os.getpid();
-    }
-
-    /**
-     * Abstract base class for all the TranscodingRequest.
-     * <p> TranscodingRequest encapsulates the desired configuration for the transcoding.
-     */
-    public abstract static class TranscodingRequest {
-        /**
-         *
-         * Default transcoding type.
-         * @hide
-         */
-        public static final int TRANSCODING_TYPE_UNKNOWN = 0;
-
-        /**
-         * TRANSCODING_TYPE_VIDEO indicates that client wants to perform transcoding on a video.
-         * <p>Note that currently only support transcoding video file in mp4 format.
-         * @hide
-         */
-        public static final int TRANSCODING_TYPE_VIDEO = 1;
-
-        /**
-         * TRANSCODING_TYPE_IMAGE indicates that client wants to perform transcoding on an image.
-         * @hide
-         */
-        public static final int TRANSCODING_TYPE_IMAGE = 2;
-
-        /** @hide */
-        @IntDef(prefix = {"TRANSCODING_TYPE_"}, value = {
-                TRANSCODING_TYPE_UNKNOWN,
-                TRANSCODING_TYPE_VIDEO,
-                TRANSCODING_TYPE_IMAGE,
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface TranscodingType {}
-
-        /**
-         * Default value.
-         *
-         * @hide
-         */
-        public static final int PRIORITY_UNKNOWN = 0;
-        /**
-         * PRIORITY_REALTIME indicates that the transcoding request is time-critical and that the
-         * client wants the transcoding result as soon as possible.
-         * <p> Set PRIORITY_REALTIME only if the transcoding is time-critical as it will involve
-         * performance penalty due to resource reallocation to prioritize the sessions with higher
-         * priority.
-         *
-         * @hide
-         */
-        public static final int PRIORITY_REALTIME = 1;
-
-        /**
-         * PRIORITY_OFFLINE indicates the transcoding is not time-critical and the client does not
-         * need the transcoding result as soon as possible.
-         * <p>Sessions with PRIORITY_OFFLINE will be scheduled behind PRIORITY_REALTIME. Always set
-         * to
-         * PRIORITY_OFFLINE if client does not need the result as soon as possible and could accept
-         * delay of the transcoding result.
-         *
-         * @hide
-         *
-         */
-        public static final int PRIORITY_OFFLINE = 2;
-
-        /** @hide */
-        @IntDef(prefix = {"PRIORITY_"}, value = {
-                PRIORITY_UNKNOWN,
-                PRIORITY_REALTIME,
-                PRIORITY_OFFLINE,
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface TranscodingPriority {}
-
-        /** Uri of the source media file. */
-        private @NonNull Uri mSourceUri;
-
-        /** Uri of the destination media file. */
-        private @NonNull Uri mDestinationUri;
-
-        /** FileDescriptor of the source media file. */
-        private @Nullable ParcelFileDescriptor mSourceFileDescriptor;
-
-        /** FileDescriptor of the destination media file. */
-        private @Nullable ParcelFileDescriptor mDestinationFileDescriptor;
-
-        /**
-         *  The UID of the client that the TranscodingRequest is for. Only privileged caller could
-         *  set this Uid as only they could do the transcoding on behalf of the client.
-         *  -1 means not available.
-         */
-        private int mClientUid = -1;
-
-        /**
-         *  The Pid of the client that the TranscodingRequest is for. Only privileged caller could
-         *  set this Uid as only they could do the transcoding on behalf of the client.
-         *  -1 means not available.
-         */
-        private int mClientPid = -1;
-
-        /** Type of the transcoding. */
-        private @TranscodingType int mType = TRANSCODING_TYPE_UNKNOWN;
-
-        /** Priority of the transcoding. */
-        private @TranscodingPriority int mPriority = PRIORITY_UNKNOWN;
-
-        /**
-         * Desired image format for the destination file.
-         * <p> If this is null, source file's image track will be passed through and copied to the
-         * destination file.
-         * @hide
-         */
-        private @Nullable MediaFormat mImageFormat = null;
-
-        @VisibleForTesting
-        private TranscodingTestConfig mTestConfig = null;
-
-        /**
-         * Prevent public constructor access.
-         */
-        /* package private */ TranscodingRequest() {
-        }
-
-        private TranscodingRequest(Builder b) {
-            mSourceUri = b.mSourceUri;
-            mSourceFileDescriptor = b.mSourceFileDescriptor;
-            mDestinationUri = b.mDestinationUri;
-            mDestinationFileDescriptor = b.mDestinationFileDescriptor;
-            mClientUid = b.mClientUid;
-            mClientPid = b.mClientPid;
-            mPriority = b.mPriority;
-            mType = b.mType;
-            mTestConfig = b.mTestConfig;
-        }
-
-        /**
-         * Return the type of the transcoding.
-         * @hide
-         */
-        @TranscodingType
-        public int getType() {
-            return mType;
-        }
-
-        /** Return source uri of the transcoding. */
-        @NonNull
-        public Uri getSourceUri() {
-            return mSourceUri;
-        }
-
-        /**
-         * Return source file descriptor of the transcoding.
-         * This will be null if client has not provided it.
-         */
-        @Nullable
-        public ParcelFileDescriptor getSourceFileDescriptor() {
-            return mSourceFileDescriptor;
-        }
-
-        /** Return the UID of the client that this request is for. -1 means not available. */
-        public int getClientUid() {
-            return mClientUid;
-        }
-
-        /** Return the PID of the client that this request is for. -1 means not available. */
-        public int getClientPid() {
-            return mClientPid;
-        }
-
-        /** Return destination uri of the transcoding. */
-        @NonNull
-        public Uri getDestinationUri() {
-            return mDestinationUri;
-        }
-
-        /**
-         * Return destination file descriptor of the transcoding.
-         * This will be null if client has not provided it.
-         */
-        @Nullable
-        public ParcelFileDescriptor getDestinationFileDescriptor() {
-            return mDestinationFileDescriptor;
-        }
-
-        /**
-         * Return priority of the transcoding.
-         * @hide
-         */
-        @TranscodingPriority
-        public int getPriority() {
-            return mPriority;
-        }
-
-        /**
-         * Return TestConfig of the transcoding.
-         * @hide
-         */
-        @Nullable
-        public TranscodingTestConfig getTestConfig() {
-            return mTestConfig;
-        }
-
-        abstract void writeFormatToParcel(TranscodingRequestParcel parcel);
-
-        /* Writes the TranscodingRequest to a parcel. */
-        private TranscodingRequestParcel writeToParcel(@NonNull Context context) {
-            TranscodingRequestParcel parcel = new TranscodingRequestParcel();
-            switch (mPriority) {
-            case PRIORITY_OFFLINE:
-                parcel.priority = TranscodingSessionPriority.kUnspecified;
-                break;
-            case PRIORITY_REALTIME:
-            case PRIORITY_UNKNOWN:
-            default:
-                parcel.priority = TranscodingSessionPriority.kNormal;
-                break;
-            }
-            parcel.transcodingType = mType;
-            parcel.sourceFilePath = mSourceUri.toString();
-            parcel.sourceFd = mSourceFileDescriptor;
-            parcel.destinationFilePath = mDestinationUri.toString();
-            parcel.destinationFd = mDestinationFileDescriptor;
-            parcel.clientUid = mClientUid;
-            parcel.clientPid = mClientPid;
-            if (mClientUid < 0) {
-                parcel.clientPackageName = context.getPackageName();
-            } else {
-                String packageName = context.getPackageManager().getNameForUid(mClientUid);
-                // PackageName is optional as some uid does not have package name. Set to
-                // "Unavailable" string in this case.
-                if (packageName == null) {
-                    Log.w(TAG, "Failed to find package for uid: " + mClientUid);
-                    packageName = "Unavailable";
-                }
-                parcel.clientPackageName = packageName;
-            }
-            writeFormatToParcel(parcel);
-            if (mTestConfig != null) {
-                parcel.isForTesting = true;
-                parcel.testConfig = mTestConfig;
-            }
-            return parcel;
-        }
-
-        /**
-         * Builder to build a {@link TranscodingRequest} object.
-         *
-         * @param <T> The subclass to be built.
-         */
-        abstract static class Builder<T extends Builder<T>> {
-            private @NonNull Uri mSourceUri;
-            private @NonNull Uri mDestinationUri;
-            private @Nullable ParcelFileDescriptor mSourceFileDescriptor = null;
-            private @Nullable ParcelFileDescriptor mDestinationFileDescriptor = null;
-            private int mClientUid = -1;
-            private int mClientPid = -1;
-            private @TranscodingType int mType = TRANSCODING_TYPE_UNKNOWN;
-            private @TranscodingPriority int mPriority = PRIORITY_UNKNOWN;
-            private TranscodingTestConfig mTestConfig;
-
-            abstract T self();
-
-            /**
-             * Creates a builder for building {@link TranscodingRequest}s.
-             *
-             * Client must set the source Uri. If client also provides the source fileDescriptor
-             * through is provided by {@link #setSourceFileDescriptor(ParcelFileDescriptor)},
-             * TranscodingSession will use the fd instead of calling back to the client to open the
-             * sourceUri.
-             *
-             *
-             * @param type The transcoding type.
-             * @param sourceUri Content uri for the source media file.
-             * @param destinationUri Content uri for the destination media file.
-             *
-             */
-            private Builder(@TranscodingType int type, @NonNull Uri sourceUri,
-                    @NonNull Uri destinationUri) {
-                mType = type;
-
-                if (sourceUri == null || Uri.EMPTY.equals(sourceUri)) {
-                    throw new IllegalArgumentException(
-                            "You must specify a non-empty source Uri.");
-                }
-                mSourceUri = sourceUri;
-
-                if (destinationUri == null || Uri.EMPTY.equals(destinationUri)) {
-                    throw new IllegalArgumentException(
-                            "You must specify a non-empty destination Uri.");
-                }
-                mDestinationUri = destinationUri;
-            }
-
-            /**
-             * Specifies the fileDescriptor opened from the source media file.
-             *
-             * This call is optional. If the source fileDescriptor is provided, TranscodingSession
-             * will use it directly instead of opening the uri from {@link #Builder(int, Uri, Uri)}.
-             * It is client's responsibility to make sure the fileDescriptor is opened from the
-             * source uri.
-             * @param fileDescriptor a {@link ParcelFileDescriptor} opened from source media file.
-             * @return The same builder instance.
-             * @throws IllegalArgumentException if fileDescriptor is invalid.
-             */
-            @NonNull
-            public T setSourceFileDescriptor(@NonNull ParcelFileDescriptor fileDescriptor) {
-                if (fileDescriptor == null || fileDescriptor.getFd() < 0) {
-                    throw new IllegalArgumentException(
-                            "Invalid source descriptor.");
-                }
-                mSourceFileDescriptor = fileDescriptor;
-                return self();
-            }
-
-            /**
-             * Specifies the fileDescriptor opened from the destination media file.
-             *
-             * This call is optional. If the destination fileDescriptor is provided,
-             * TranscodingSession will use it directly instead of opening the source uri from
-             * {@link #Builder(int, Uri, Uri)} upon transcoding starts. It is client's
-             * responsibility to make sure the fileDescriptor is opened from the destination uri.
-             * @param fileDescriptor a {@link ParcelFileDescriptor} opened from destination media
-             *                       file.
-             * @return The same builder instance.
-             * @throws IllegalArgumentException if fileDescriptor is invalid.
-             */
-            @NonNull
-            public T setDestinationFileDescriptor(
-                    @NonNull ParcelFileDescriptor fileDescriptor) {
-                if (fileDescriptor == null || fileDescriptor.getFd() < 0) {
-                    throw new IllegalArgumentException(
-                            "Invalid destination descriptor.");
-                }
-                mDestinationFileDescriptor = fileDescriptor;
-                return self();
-            }
-
-            /**
-             * Specify the UID of the client that this request is for.
-             * <p>
-             * Only privilege caller with android.permission.WRITE_MEDIA_STORAGE could forward the
-             * pid. Note that the permission check happens on the service side upon starting the
-             * transcoding. If the client does not have the permission, the transcoding will fail.
-             *
-             * @param uid client Uid.
-             * @return The same builder instance.
-             * @throws IllegalArgumentException if uid is invalid.
-             */
-            @NonNull
-            public T setClientUid(int uid) {
-                if (uid < 0) {
-                    throw new IllegalArgumentException("Invalid Uid");
-                }
-                mClientUid = uid;
-                return self();
-            }
-
-            /**
-             * Specify the pid of the client that this request is for.
-             * <p>
-             * Only privilege caller with android.permission.WRITE_MEDIA_STORAGE could forward the
-             * pid. Note that the permission check happens on the service side upon starting the
-             * transcoding. If the client does not have the permission, the transcoding will fail.
-             *
-             * @param pid client Pid.
-             * @return The same builder instance.
-             * @throws IllegalArgumentException if pid is invalid.
-             */
-            @NonNull
-            public T setClientPid(int pid) {
-                if (pid < 0) {
-                    throw new IllegalArgumentException("Invalid pid");
-                }
-                mClientPid = pid;
-                return self();
-            }
-
-            /**
-             * Specifies the priority of the transcoding.
-             *
-             * @param priority Must be one of the {@code PRIORITY_*}
-             * @return The same builder instance.
-             * @throws IllegalArgumentException if flags is invalid.
-             * @hide
-             */
-            @NonNull
-            public T setPriority(@TranscodingPriority int priority) {
-                if (priority != PRIORITY_OFFLINE && priority != PRIORITY_REALTIME) {
-                    throw new IllegalArgumentException("Invalid priority: " + priority);
-                }
-                mPriority = priority;
-                return self();
-            }
-
-            /**
-             * Sets the delay in processing this request.
-             * @param config test config.
-             * @return The same builder instance.
-             * @hide
-             */
-            @VisibleForTesting
-            @NonNull
-            public T setTestConfig(@NonNull TranscodingTestConfig config) {
-                mTestConfig = config;
-                return self();
-            }
-        }
-
-        /**
-         * Abstract base class for all the format resolvers.
-         */
-        abstract static class MediaFormatResolver {
-            private @NonNull ApplicationMediaCapabilities mClientCaps;
-
-            /**
-             * Prevents public constructor access.
-             */
-            /* package private */ MediaFormatResolver() {
-            }
-
-            /**
-             * Constructs MediaFormatResolver object.
-             *
-             * @param clientCaps An ApplicationMediaCapabilities object containing the client's
-             *                   capabilities.
-             */
-            MediaFormatResolver(@NonNull ApplicationMediaCapabilities clientCaps) {
-                if (clientCaps == null) {
-                    throw new IllegalArgumentException("Client capabilities must not be null");
-                }
-                mClientCaps = clientCaps;
-            }
-
-            /**
-             * Returns the client capabilities.
-             */
-            @NonNull
-            /* package */ ApplicationMediaCapabilities getClientCapabilities() {
-                return mClientCaps;
-            }
-
-            abstract boolean shouldTranscode();
-        }
-
-        /**
-         * VideoFormatResolver for deciding if video transcoding is needed, and if so, the track
-         * formats to use.
-         */
-        public static class VideoFormatResolver extends MediaFormatResolver {
-            private static final int BIT_RATE = 20000000;            // 20Mbps
-
-            private MediaFormat mSrcVideoFormatHint;
-            private MediaFormat mSrcAudioFormatHint;
-
-            /**
-             * Constructs a new VideoFormatResolver object.
-             *
-             * @param clientCaps An ApplicationMediaCapabilities object containing the client's
-             *                   capabilities.
-             * @param srcVideoFormatHint A MediaFormat object containing information about the
-             *                           source's video track format that could affect the
-             *                           transcoding decision. Such information could include video
-             *                           codec types, color spaces, whether special format info (eg.
-             *                           slow-motion markers) are present, etc.. If a particular
-             *                           information is not present, it will not be used to make the
-             *                           decision.
-             */
-            public VideoFormatResolver(@NonNull ApplicationMediaCapabilities clientCaps,
-                    @NonNull MediaFormat srcVideoFormatHint) {
-                super(clientCaps);
-                mSrcVideoFormatHint = srcVideoFormatHint;
-            }
-
-            /**
-             * Constructs a new VideoFormatResolver object.
-             *
-             * @param clientCaps An ApplicationMediaCapabilities object containing the client's
-             *                   capabilities.
-             * @param srcVideoFormatHint A MediaFormat object containing information about the
-             *                           source's video track format that could affect the
-             *                           transcoding decision. Such information could include video
-             *                           codec types, color spaces, whether special format info (eg.
-             *                           slow-motion markers) are present, etc.. If a particular
-             *                           information is not present, it will not be used to make the
-             *                           decision.
-             * @param srcAudioFormatHint A MediaFormat object containing information about the
-             *                           source's audio track format that could affect the
-             *                           transcoding decision.
-             * @hide
-             */
-            VideoFormatResolver(@NonNull ApplicationMediaCapabilities clientCaps,
-                    @NonNull MediaFormat srcVideoFormatHint,
-                    @NonNull MediaFormat srcAudioFormatHint) {
-                super(clientCaps);
-                mSrcVideoFormatHint = srcVideoFormatHint;
-                mSrcAudioFormatHint = srcAudioFormatHint;
-            }
-
-            /**
-             * Returns whether the source content should be transcoded.
-             *
-             * @return true if the source should be transcoded.
-             */
-            public boolean shouldTranscode() {
-                boolean supportHevc = getClientCapabilities().isVideoMimeTypeSupported(
-                        MediaFormat.MIMETYPE_VIDEO_HEVC);
-                if (!supportHevc && MediaFormat.MIMETYPE_VIDEO_HEVC.equals(
-                        mSrcVideoFormatHint.getString(MediaFormat.KEY_MIME))) {
-                    return true;
-                }
-                // TODO: add more checks as needed below.
-                return false;
-            }
-
-            /**
-             * Retrieves the video track format to be used on
-             * {@link VideoTranscodingRequest.Builder#setVideoTrackFormat(MediaFormat)} for this
-             * configuration.
-             *
-             * @return the video track format to be used if transcoding should be performed,
-             *         and null otherwise.
-             * @throws IllegalArgumentException if the hinted source video format contains invalid
-             *         parameters.
-             */
-            @Nullable
-            public MediaFormat resolveVideoFormat() {
-                if (!shouldTranscode()) {
-                    return null;
-                }
-
-                MediaFormat videoTrackFormat = new MediaFormat(mSrcVideoFormatHint);
-                videoTrackFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_AVC);
-
-                int width = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_WIDTH, -1);
-                int height = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_HEIGHT, -1);
-                if (width <= 0 || height <= 0) {
-                    throw new IllegalArgumentException(
-                            "Source Width and height must be larger than 0");
-                }
-
-                float frameRate =
-                        mSrcVideoFormatHint.getNumber(MediaFormat.KEY_FRAME_RATE, 30.0)
-                        .floatValue();
-                if (frameRate <= 0) {
-                    throw new IllegalArgumentException(
-                            "frameRate must be larger than 0");
-                }
-
-                int bitrate = getAVCBitrate(width, height, frameRate);
-                videoTrackFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
-                return videoTrackFormat;
-            }
-
-            /**
-             * Generate a default bitrate with the fixed bpp(bits-per-pixel) 0.25.
-             * This maps to:
-             * 1080P@30fps -> 16Mbps
-             * 1080P@60fps-> 32Mbps
-             * 4K@30fps -> 62Mbps
-             */
-            private static int getDefaultBitrate(int width, int height, float frameRate) {
-                return (int) (width * height * frameRate * BPP);
-            }
-
-            /**
-             * Query the bitrate from CamcorderProfile. If there are two profiles that match the
-             * width/height/framerate, we will use the higher one to get better quality.
-             * Return default bitrate if could not find any match profile.
-             */
-            private static int getAVCBitrate(int width, int height, float frameRate) {
-                int bitrate = -1;
-                int[] cameraIds = {0, 1};
-
-                // Profiles ordered in decreasing order of preference.
-                int[] preferQualities = {
-                        CamcorderProfile.QUALITY_2160P,
-                        CamcorderProfile.QUALITY_1080P,
-                        CamcorderProfile.QUALITY_720P,
-                        CamcorderProfile.QUALITY_480P,
-                        CamcorderProfile.QUALITY_LOW,
-                };
-
-                for (int cameraId : cameraIds) {
-                    for (int quality : preferQualities) {
-                        // Check if camera id has profile for the quality level.
-                        if (!CamcorderProfile.hasProfile(cameraId, quality)) {
-                            continue;
-                        }
-                        CamcorderProfile profile = CamcorderProfile.get(cameraId, quality);
-                        // Check the width/height/framerate/codec, also consider portrait case.
-                        if (((width == profile.videoFrameWidth
-                                && height == profile.videoFrameHeight)
-                                || (height == profile.videoFrameWidth
-                                && width == profile.videoFrameHeight))
-                                && (int) frameRate == profile.videoFrameRate
-                                && profile.videoCodec == MediaRecorder.VideoEncoder.H264) {
-                            if (bitrate < profile.videoBitRate) {
-                                bitrate = profile.videoBitRate;
-                            }
-                            break;
-                        }
-                    }
-                }
-
-                if (bitrate == -1) {
-                    Log.w(TAG, "Failed to find CamcorderProfile for w: " + width + "h: " + height
-                            + " fps: "
-                            + frameRate);
-                    bitrate = getDefaultBitrate(width, height, frameRate);
-                }
-                Log.d(TAG, "Using bitrate " + bitrate + " for " + width + " " + height + " "
-                        + frameRate);
-                return bitrate;
-            }
-
-            /**
-             * Retrieves the audio track format to be used for transcoding.
-             *
-             * @return the audio track format to be used if transcoding should be performed, and
-             *         null otherwise.
-             * @hide
-             */
-            @Nullable
-            public MediaFormat resolveAudioFormat() {
-                if (!shouldTranscode()) {
-                    return null;
-                }
-                // Audio transcoding is not supported yet, always return null.
-                return null;
-            }
-        }
-    }
-
-    /**
-     * VideoTranscodingRequest encapsulates the configuration for transcoding a video.
-     */
-    public static final class VideoTranscodingRequest extends TranscodingRequest {
-        /**
-         * Desired output video format of the destination file.
-         * <p> If this is null, source file's video track will be passed through and copied to the
-         * destination file.
-         */
-        private @Nullable MediaFormat mVideoTrackFormat = null;
-
-        /**
-         * Desired output audio format of the destination file.
-         * <p> If this is null, source file's audio track will be passed through and copied to the
-         * destination file.
-         */
-        private @Nullable MediaFormat mAudioTrackFormat = null;
-
-        private VideoTranscodingRequest(VideoTranscodingRequest.Builder builder) {
-            super(builder);
-            mVideoTrackFormat = builder.mVideoTrackFormat;
-            mAudioTrackFormat = builder.mAudioTrackFormat;
-        }
-
-        /**
-         * Return the video track format of the transcoding.
-         * This will be null if client has not specified the video track format.
-         */
-        @NonNull
-        public MediaFormat getVideoTrackFormat() {
-            return mVideoTrackFormat;
-        }
-
-        @Override
-        void writeFormatToParcel(TranscodingRequestParcel parcel) {
-            parcel.requestedVideoTrackFormat = convertToVideoTrackFormat(mVideoTrackFormat);
-        }
-
-        /* Converts the MediaFormat to TranscodingVideoTrackFormat. */
-        private static TranscodingVideoTrackFormat convertToVideoTrackFormat(MediaFormat format) {
-            if (format == null) {
-                throw new IllegalArgumentException("Invalid MediaFormat");
-            }
-
-            TranscodingVideoTrackFormat trackFormat = new TranscodingVideoTrackFormat();
-
-            if (format.containsKey(MediaFormat.KEY_MIME)) {
-                String mime = format.getString(MediaFormat.KEY_MIME);
-                if (MediaFormat.MIMETYPE_VIDEO_AVC.equals(mime)) {
-                    trackFormat.codecType = TranscodingVideoCodecType.kAvc;
-                } else if (MediaFormat.MIMETYPE_VIDEO_HEVC.equals(mime)) {
-                    trackFormat.codecType = TranscodingVideoCodecType.kHevc;
-                } else {
-                    throw new UnsupportedOperationException("Only support transcode to avc/hevc");
-                }
-            }
-
-            if (format.containsKey(MediaFormat.KEY_BIT_RATE)) {
-                int bitrateBps = format.getInteger(MediaFormat.KEY_BIT_RATE);
-                if (bitrateBps <= 0) {
-                    throw new IllegalArgumentException("Bitrate must be larger than 0");
-                }
-                trackFormat.bitrateBps = bitrateBps;
-            }
-
-            if (format.containsKey(MediaFormat.KEY_WIDTH) && format.containsKey(
-                    MediaFormat.KEY_HEIGHT)) {
-                int width = format.getInteger(MediaFormat.KEY_WIDTH);
-                int height = format.getInteger(MediaFormat.KEY_HEIGHT);
-                if (width <= 0 || height <= 0) {
-                    throw new IllegalArgumentException("Width and height must be larger than 0");
-                }
-                // TODO: Validate the aspect ratio after adding scaling.
-                trackFormat.width = width;
-                trackFormat.height = height;
-            }
-
-            if (format.containsKey(MediaFormat.KEY_PROFILE)) {
-                int profile = format.getInteger(MediaFormat.KEY_PROFILE);
-                if (profile <= 0) {
-                    throw new IllegalArgumentException("Invalid codec profile");
-                }
-                // TODO: Validate the profile according to codec type.
-                trackFormat.profile = profile;
-            }
-
-            if (format.containsKey(MediaFormat.KEY_LEVEL)) {
-                int level = format.getInteger(MediaFormat.KEY_LEVEL);
-                if (level <= 0) {
-                    throw new IllegalArgumentException("Invalid codec level");
-                }
-                // TODO: Validate the level according to codec type.
-                trackFormat.level = level;
-            }
-
-            return trackFormat;
-        }
-
-        /**
-         * Builder class for {@link VideoTranscodingRequest}.
-         */
-        public static final class Builder extends
-                TranscodingRequest.Builder<VideoTranscodingRequest.Builder> {
-            /**
-             * Desired output video format of the destination file.
-             * <p> If this is null, source file's video track will be passed through and
-             * copied to the destination file.
-             */
-            private @Nullable MediaFormat mVideoTrackFormat = null;
-
-            /**
-             * Desired output audio format of the destination file.
-             * <p> If this is null, source file's audio track will be passed through and copied
-             * to the destination file.
-             */
-            private @Nullable MediaFormat mAudioTrackFormat = null;
-
-            /**
-             * Creates a builder for building {@link VideoTranscodingRequest}s.
-             *
-             * <p> Client could only specify the settings that matters to them, e.g. codec format or
-             * bitrate. And by default, transcoding will preserve the original video's settings
-             * (bitrate, framerate, resolution) if not provided.
-             * <p>Note that some settings may silently fail to apply if the device does not support
-             * them.
-             * @param sourceUri Content uri for the source media file.
-             * @param destinationUri Content uri for the destination media file.
-             * @param videoFormat MediaFormat containing the settings that client wants override in
-             *                    the original video's video track.
-             * @throws IllegalArgumentException if videoFormat is invalid.
-             */
-            public Builder(@NonNull Uri sourceUri, @NonNull Uri destinationUri,
-                    @NonNull MediaFormat videoFormat) {
-                super(TRANSCODING_TYPE_VIDEO, sourceUri, destinationUri);
-                setVideoTrackFormat(videoFormat);
-            }
-
-            @Override
-            @NonNull
-            public Builder setClientUid(int uid) {
-                super.setClientUid(uid);
-                return self();
-            }
-
-            @Override
-            @NonNull
-            public Builder setClientPid(int pid) {
-                super.setClientPid(pid);
-                return self();
-            }
-
-            @Override
-            @NonNull
-            public Builder setSourceFileDescriptor(@NonNull ParcelFileDescriptor fd) {
-                super.setSourceFileDescriptor(fd);
-                return self();
-            }
-
-            @Override
-            @NonNull
-            public Builder setDestinationFileDescriptor(@NonNull ParcelFileDescriptor fd) {
-                super.setDestinationFileDescriptor(fd);
-                return self();
-            }
-
-            private void setVideoTrackFormat(@NonNull MediaFormat videoFormat) {
-                if (videoFormat == null) {
-                    throw new IllegalArgumentException("videoFormat must not be null");
-                }
-
-                // Check if the MediaFormat is for video by looking at the MIME type.
-                String mime = videoFormat.containsKey(MediaFormat.KEY_MIME)
-                        ? videoFormat.getString(MediaFormat.KEY_MIME) : null;
-                if (mime == null || !mime.startsWith("video/")) {
-                    throw new IllegalArgumentException("Invalid video format: wrong mime type");
-                }
-
-                mVideoTrackFormat = videoFormat;
-            }
-
-            /**
-             * @return a new {@link TranscodingRequest} instance successfully initialized
-             * with all the parameters set on this <code>Builder</code>.
-             * @throws UnsupportedOperationException if the parameters set on the
-             *                                       <code>Builder</code> were incompatible, or
-             *                                       if they are not supported by the
-             *                                       device.
-             */
-            @NonNull
-            public VideoTranscodingRequest build() {
-                return new VideoTranscodingRequest(this);
-            }
-
-            @Override
-            VideoTranscodingRequest.Builder self() {
-                return this;
-            }
-        }
-    }
-
-    /**
-     * Handle to an enqueued transcoding operation. An instance of this class represents a single
-     * enqueued transcoding operation. The caller can use that instance to query the status or
-     * progress, and to get the result once the operation has completed.
-     */
-    public static final class TranscodingSession {
-        /** The session is enqueued but not yet running. */
-        public static final int STATUS_PENDING = 1;
-        /** The session is currently running. */
-        public static final int STATUS_RUNNING = 2;
-        /** The session is finished. */
-        public static final int STATUS_FINISHED = 3;
-        /** The session is paused. */
-        public static final int STATUS_PAUSED = 4;
-
-        /** @hide */
-        @IntDef(prefix = { "STATUS_" }, value = {
-                STATUS_PENDING,
-                STATUS_RUNNING,
-                STATUS_FINISHED,
-                STATUS_PAUSED,
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface Status {}
-
-        /** The session does not have a result yet. */
-        public static final int RESULT_NONE = 1;
-        /** The session completed successfully. */
-        public static final int RESULT_SUCCESS = 2;
-        /** The session encountered an error while running. */
-        public static final int RESULT_ERROR = 3;
-        /** The session was canceled by the caller. */
-        public static final int RESULT_CANCELED = 4;
-
-        /** @hide */
-        @IntDef(prefix = { "RESULT_" }, value = {
-                RESULT_NONE,
-                RESULT_SUCCESS,
-                RESULT_ERROR,
-                RESULT_CANCELED,
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface Result {}
-
-
-        // The error code exposed here should be in sync with:
-        // frameworks/av/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
-        /** @hide */
-        @IntDef(prefix = { "TRANSCODING_SESSION_ERROR_" }, value = {
-                ERROR_NONE,
-                ERROR_DROPPED_BY_SERVICE,
-                ERROR_SERVICE_DIED})
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface TranscodingSessionErrorCode{}
-        /**
-         * Constant indicating that no error occurred.
-         */
-        public static final int ERROR_NONE = 0;
-
-        /**
-         * Constant indicating that the session is dropped by Transcoding service due to hitting
-         * the limit, e.g. too many back to back transcoding happen in a short time frame.
-         */
-        public static final int ERROR_DROPPED_BY_SERVICE = 1;
-
-        /**
-         * Constant indicating the backing transcoding service is died. Client should enqueue the
-         * the request again.
-         */
-        public static final int ERROR_SERVICE_DIED = 2;
-
-        /** Listener that gets notified when the progress changes. */
-        @FunctionalInterface
-        public interface OnProgressUpdateListener {
-            /**
-             * Called when the progress changes. The progress is in percentage between 0 and 1,
-             * where 0 means the session has not yet started and 100 means that it has finished.
-             *
-             * @param session      The session associated with the progress.
-             * @param progress The new progress ranging from 0 ~ 100 inclusive.
-             */
-            void onProgressUpdate(@NonNull TranscodingSession session,
-                    @IntRange(from = 0, to = 100) int progress);
-        }
-
-        private final MediaTranscodingManager mManager;
-        private Executor mListenerExecutor;
-        private OnTranscodingFinishedListener mListener;
-        private int mSessionId = -1;
-        // Lock for internal state.
-        private final Object mLock = new Object();
-        @GuardedBy("mLock")
-        private Executor mProgressUpdateExecutor = null;
-        @GuardedBy("mLock")
-        private OnProgressUpdateListener mProgressUpdateListener = null;
-        @GuardedBy("mLock")
-        private int mProgress = 0;
-        @GuardedBy("mLock")
-        private int mProgressUpdateInterval = 0;
-        @GuardedBy("mLock")
-        private @Status int mStatus = STATUS_PENDING;
-        @GuardedBy("mLock")
-        private @Result int mResult = RESULT_NONE;
-        @GuardedBy("mLock")
-        private @TranscodingSessionErrorCode int mErrorCode = ERROR_NONE;
-        @GuardedBy("mLock")
-        private boolean mHasRetried = false;
-        // The original request that associated with this session.
-        private final TranscodingRequest mRequest;
-
-        private TranscodingSession(
-                @NonNull MediaTranscodingManager manager,
-                @NonNull TranscodingRequest request,
-                @NonNull TranscodingSessionParcel parcel,
-                @NonNull @CallbackExecutor Executor executor,
-                @NonNull OnTranscodingFinishedListener listener) {
-            Objects.requireNonNull(manager, "manager must not be null");
-            Objects.requireNonNull(parcel, "parcel must not be null");
-            Objects.requireNonNull(executor, "listenerExecutor must not be null");
-            Objects.requireNonNull(listener, "listener must not be null");
-            mManager = manager;
-            mSessionId = parcel.sessionId;
-            mListenerExecutor = executor;
-            mListener = listener;
-            mRequest = request;
-        }
-
-        /**
-         * Set a progress listener.
-         * @param executor The executor on which listener will be invoked.
-         * @param listener The progress listener.
-         */
-        public void setOnProgressUpdateListener(
-                @NonNull @CallbackExecutor Executor executor,
-                @Nullable OnProgressUpdateListener listener) {
-            synchronized (mLock) {
-                Objects.requireNonNull(executor, "listenerExecutor must not be null");
-                Objects.requireNonNull(listener, "listener must not be null");
-                mProgressUpdateExecutor = executor;
-                mProgressUpdateListener = listener;
-            }
-        }
-
-        private void updateStatusAndResult(@Status int sessionStatus,
-                @Result int sessionResult, @TranscodingSessionErrorCode int errorCode) {
-            synchronized (mLock) {
-                mStatus = sessionStatus;
-                mResult = sessionResult;
-                mErrorCode = errorCode;
-            }
-        }
-
-        /**
-         * Retrieve the error code associated with the RESULT_ERROR.
-         */
-        public @TranscodingSessionErrorCode int getErrorCode() {
-            synchronized (mLock) {
-                return mErrorCode;
-            }
-        }
-
-        /**
-         * Resubmit the transcoding session to the service.
-         * Note that only the session that fails or gets cancelled could be retried and each session
-         * could be retried only once. After that, Client need to enqueue a new request if they want
-         * to try again.
-         *
-         * @return true if successfully resubmit the job to service. False otherwise.
-         * @throws UnsupportedOperationException if the retry could not be fulfilled.
-         * @hide
-         */
-        public boolean retry() {
-            return retryInternal(true /*setHasRetried*/);
-        }
-
-        // TODO(hkuang): Add more test for it.
-        private boolean retryInternal(boolean setHasRetried) {
-            synchronized (mLock) {
-                if (mStatus == STATUS_PENDING || mStatus == STATUS_RUNNING) {
-                    throw new UnsupportedOperationException(
-                            "Failed to retry as session is in processing");
-                }
-
-                if (mHasRetried) {
-                    throw new UnsupportedOperationException("Session has been retried already");
-                }
-
-                // Get the client interface.
-                ITranscodingClient client = mManager.getTranscodingClient();
-                if (client == null) {
-                    Log.e(TAG, "Service rebooting. Try again later");
-                    return false;
-                }
-
-                synchronized (mManager.mPendingTranscodingSessions) {
-                    try {
-                        // Submits the request to MediaTranscoding service.
-                        TranscodingSessionParcel sessionParcel = new TranscodingSessionParcel();
-                        if (!client.submitRequest(mRequest.writeToParcel(mManager.mContext),
-                                                  sessionParcel)) {
-                            mHasRetried = true;
-                            throw new UnsupportedOperationException("Failed to enqueue request");
-                        }
-
-                        // Replace the old session id wit the new one.
-                        mSessionId = sessionParcel.sessionId;
-                        // Adds the new session back into pending sessions.
-                        mManager.mPendingTranscodingSessions.put(mSessionId, this);
-                    } catch (RemoteException re) {
-                        return false;
-                    }
-                    mStatus = STATUS_PENDING;
-                    mHasRetried = setHasRetried ? true : false;
-                }
-            }
-            return true;
-        }
-
-        /**
-         * Cancels the transcoding session and notify the listener.
-         * If the session happened to finish before being canceled this call is effectively a no-op
-         * and will not update the result in that case.
-         */
-        public void cancel() {
-            synchronized (mLock) {
-                // Check if the session is finished already.
-                if (mStatus != STATUS_FINISHED) {
-                    try {
-                        ITranscodingClient client = mManager.getTranscodingClient();
-                        // The client may be gone.
-                        if (client != null) {
-                            client.cancelSession(mSessionId);
-                        }
-                    } catch (RemoteException re) {
-                        //TODO(hkuang): Find out what to do if failing to cancel the session.
-                        Log.e(TAG, "Failed to cancel the session due to exception:  " + re);
-                    }
-                    mStatus = STATUS_FINISHED;
-                    mResult = RESULT_CANCELED;
-
-                    // Notifies client the session is canceled.
-                    mListenerExecutor.execute(() -> mListener.onTranscodingFinished(this));
-                }
-            }
-        }
-
-        /**
-         * Gets the progress of the transcoding session. The progress is between 0 and 100, where 0
-         * means that the session has not yet started and 100 means that it is finished. For the
-         * cancelled session, the progress will be the last updated progress before it is cancelled.
-         * @return The progress.
-         */
-        @IntRange(from = 0, to = 100)
-        public int getProgress() {
-            synchronized (mLock) {
-                return mProgress;
-            }
-        }
-
-        /**
-         * Gets the status of the transcoding session.
-         * @return The status.
-         */
-        public @Status int getStatus() {
-            synchronized (mLock) {
-                return mStatus;
-            }
-        }
-
-        /**
-         * Adds a client uid that is also waiting for this transcoding session.
-         * <p>
-         * Only privilege caller with android.permission.WRITE_MEDIA_STORAGE could add the
-         * uid. Note that the permission check happens on the service side upon starting the
-         * transcoding. If the client does not have the permission, the transcoding will fail.
-         * @param uid  the additional client uid to be added.
-         * @return true if successfully added, false otherwise.
-         */
-        public boolean addClientUid(int uid) {
-            if (uid < 0) {
-                throw new IllegalArgumentException("Invalid Uid");
-            }
-
-            // Get the client interface.
-            ITranscodingClient client = mManager.getTranscodingClient();
-            if (client == null) {
-                Log.e(TAG, "Service is dead...");
-                return false;
-            }
-
-            try {
-                if (!client.addClientUid(mSessionId, uid)) {
-                    Log.e(TAG, "Failed to add client uid");
-                    return false;
-                }
-            } catch (Exception ex) {
-                Log.e(TAG, "Failed to get client uids due to " + ex);
-                return false;
-            }
-            return true;
-        }
-
-        /**
-         * Query all the client that waiting for this transcoding session
-         * @return a list containing all the client uids.
-         */
-        @NonNull
-        public List<Integer> getClientUids() {
-            List<Integer> uidList = new ArrayList<Integer>();
-
-            // Get the client interface.
-            ITranscodingClient client = mManager.getTranscodingClient();
-            if (client == null) {
-                Log.e(TAG, "Service is dead...");
-                return uidList;
-            }
-
-            try {
-                int[] clientUids  = client.getClientUids(mSessionId);
-                for (int i : clientUids) {
-                    uidList.add(i);
-                }
-            } catch (Exception ex) {
-                Log.e(TAG, "Failed to get client uids due to " + ex);
-            }
-
-            return uidList;
-        }
-
-        /**
-         * Gets sessionId of the transcoding session.
-         * @return session id.
-         */
-        public int getSessionId() {
-            return mSessionId;
-        }
-
-        /**
-         * Gets the result of the transcoding session.
-         * @return The result.
-         */
-        public @Result int getResult() {
-            synchronized (mLock) {
-                return mResult;
-            }
-        }
-
-        @Override
-        public String toString() {
-            String result;
-            String status;
-
-            switch (mResult) {
-                case RESULT_NONE:
-                    result = "RESULT_NONE";
-                    break;
-                case RESULT_SUCCESS:
-                    result = "RESULT_SUCCESS";
-                    break;
-                case RESULT_ERROR:
-                    result = "RESULT_ERROR(" + mErrorCode + ")";
-                    break;
-                case RESULT_CANCELED:
-                    result = "RESULT_CANCELED";
-                    break;
-                default:
-                    result = String.valueOf(mResult);
-                    break;
-            }
-
-            switch (mStatus) {
-                case STATUS_PENDING:
-                    status = "STATUS_PENDING";
-                    break;
-                case STATUS_PAUSED:
-                    status = "STATUS_PAUSED";
-                    break;
-                case STATUS_RUNNING:
-                    status = "STATUS_RUNNING";
-                    break;
-                case STATUS_FINISHED:
-                    status = "STATUS_FINISHED";
-                    break;
-                default:
-                    status = String.valueOf(mStatus);
-                    break;
-            }
-            return String.format(" session: {id: %d, status: %s, result: %s, progress: %d}",
-                    mSessionId, status, result, mProgress);
-        }
-
-        private void updateProgress(int newProgress) {
-            synchronized (mLock) {
-                mProgress = newProgress;
-            }
-        }
-
-        private void updateStatus(int newStatus) {
-            synchronized (mLock) {
-                mStatus = newStatus;
-            }
-        }
-    }
-
-    private ITranscodingClient getTranscodingClient() {
-        synchronized (mLock) {
-            return mTranscodingClient;
-        }
-    }
-
-    /**
-     * Enqueues a TranscodingRequest for execution.
-     * <p> Upon successfully accepting the request, MediaTranscodingManager will return a
-     * {@link TranscodingSession} to the client. Client should use {@link TranscodingSession} to
-     * track the progress and get the result.
-     * <p> MediaTranscodingManager will return null if fails to accept the request due to service
-     * rebooting. Client could retry again after receiving null.
-     *
-     * @param transcodingRequest The TranscodingRequest to enqueue.
-     * @param listenerExecutor   Executor on which the listener is notified.
-     * @param listener           Listener to get notified when the transcoding session is finished.
-     * @return A TranscodingSession for this operation.
-     * @throws UnsupportedOperationException if the request could not be fulfilled.
-     */
-    @Nullable
-    public TranscodingSession enqueueRequest(
-            @NonNull TranscodingRequest transcodingRequest,
-            @NonNull @CallbackExecutor Executor listenerExecutor,
-            @NonNull OnTranscodingFinishedListener listener) {
-        Log.i(TAG, "enqueueRequest called.");
-        Objects.requireNonNull(transcodingRequest, "transcodingRequest must not be null");
-        Objects.requireNonNull(listenerExecutor, "listenerExecutor must not be null");
-        Objects.requireNonNull(listener, "listener must not be null");
-
-        // Converts the request to TranscodingRequestParcel.
-        TranscodingRequestParcel requestParcel = transcodingRequest.writeToParcel(mContext);
-
-        Log.i(TAG, "Getting transcoding request " + transcodingRequest.getSourceUri());
-
-        // Submits the request to MediaTranscoding service.
-        try {
-            TranscodingSessionParcel sessionParcel = new TranscodingSessionParcel();
-            // Synchronizes the access to mPendingTranscodingSessions to make sure the session Id is
-            // inserted in the mPendingTranscodingSessions in the callback handler.
-            synchronized (mPendingTranscodingSessions) {
-                synchronized (mLock) {
-                    if (mTranscodingClient == null) {
-                        // Try to register with the service again.
-                        IMediaTranscodingService service = getService(false /*retry*/);
-                        if (service == null) {
-                            Log.w(TAG, "Service rebooting. Try again later");
-                            return null;
-                        }
-                        mTranscodingClient = registerClient(service);
-                        // If still fails, throws an exception to tell client to try later.
-                        if (mTranscodingClient == null) {
-                            Log.w(TAG, "Service rebooting. Try again later");
-                            return null;
-                        }
-                    }
-
-                    if (!mTranscodingClient.submitRequest(requestParcel, sessionParcel)) {
-                        throw new UnsupportedOperationException("Failed to enqueue request");
-                    }
-                }
-
-                // Wraps the TranscodingSessionParcel into a TranscodingSession and returns it to
-                // client for tracking.
-                TranscodingSession session = new TranscodingSession(this, transcodingRequest,
-                        sessionParcel,
-                        listenerExecutor,
-                        listener);
-
-                // Adds the new session into pending sessions.
-                mPendingTranscodingSessions.put(session.getSessionId(), session);
-                return session;
-            }
-        } catch (RemoteException ex) {
-            Log.w(TAG, "Service rebooting. Try again later");
-            return null;
-        } catch (ServiceSpecificException ex) {
-            throw new UnsupportedOperationException(
-                    "Failed to submit request to Transcoding service. Error: " + ex);
-        }
-    }
-}
diff --git a/apex/media/framework/java/android/media/ProxyDataSourceCallback.java b/apex/media/framework/java/android/media/ProxyDataSourceCallback.java
deleted file mode 100644
index 14d3ce8..0000000
--- a/apex/media/framework/java/android/media/ProxyDataSourceCallback.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2019 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 android.media;
-
-import android.os.ParcelFileDescriptor;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-
-/**
- * A DataSourceCallback that is backed by a ParcelFileDescriptor.
- */
-class ProxyDataSourceCallback extends DataSourceCallback {
-    private static final String TAG = "TestDataSourceCallback";
-
-    ParcelFileDescriptor mPFD;
-    FileDescriptor mFD;
-
-    ProxyDataSourceCallback(ParcelFileDescriptor pfd) throws IOException {
-        mPFD = pfd.dup();
-        mFD = mPFD.getFileDescriptor();
-    }
-
-    @Override
-    public synchronized int readAt(long position, byte[] buffer, int offset, int size)
-            throws IOException {
-        try {
-            Os.lseek(mFD, position, OsConstants.SEEK_SET);
-            int ret = Os.read(mFD, buffer, offset, size);
-            return (ret == 0) ? END_OF_STREAM : ret;
-        } catch (ErrnoException e) {
-            throw new IOException(e);
-        }
-    }
-
-    @Override
-    public synchronized long getSize() throws IOException {
-        return mPFD.getStatSize();
-    }
-
-    @Override
-    public synchronized void close() {
-        try {
-            mPFD.close();
-        } catch (IOException e) {
-            Log.e(TAG, "Failed to close the PFD.", e);
-        }
-    }
-}
-
diff --git a/apex/media/framework/java/android/media/RoutingDelegate.java b/apex/media/framework/java/android/media/RoutingDelegate.java
deleted file mode 100644
index 2359813..0000000
--- a/apex/media/framework/java/android/media/RoutingDelegate.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 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 android.media;
-
-import android.os.Handler;
-
-class RoutingDelegate implements AudioRouting.OnRoutingChangedListener {
-    private AudioRouting mAudioRouting;
-    private AudioRouting.OnRoutingChangedListener mOnRoutingChangedListener;
-    private Handler mHandler;
-
-    RoutingDelegate(final AudioRouting audioRouting,
-                    final AudioRouting.OnRoutingChangedListener listener,
-                    Handler handler) {
-        mAudioRouting = audioRouting;
-        mOnRoutingChangedListener = listener;
-        mHandler = handler;
-    }
-
-    public AudioRouting.OnRoutingChangedListener getListener() {
-        return mOnRoutingChangedListener;
-    }
-
-    public Handler getHandler() {
-        return mHandler;
-    }
-
-    @Override
-    public void onRoutingChanged(AudioRouting router) {
-        if (mOnRoutingChangedListener != null) {
-            mOnRoutingChangedListener.onRoutingChanged(mAudioRouting);
-        }
-    }
-}
diff --git a/apex/media/framework/java/android/media/Session2Command.java b/apex/media/framework/java/android/media/Session2Command.java
deleted file mode 100644
index 7e71591..0000000
--- a/apex/media/framework/java/android/media/Session2Command.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 android.media;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-import java.util.Objects;
-
-/**
- * This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
- * Library</a> for consistent behavior across all devices.
- * <p>
- * Define a command that a {@link MediaController2} can send to a {@link MediaSession2}.
- * <p>
- * If {@link #getCommandCode()} isn't {@link #COMMAND_CODE_CUSTOM}), it's predefined command.
- * If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and
- * {@link #getCustomAction()} shouldn't be {@code null}.
- * <p>
- * Refer to the <a href="{@docRoot}reference/androidx/media2/session/SessionCommand.html">
- * AndroidX SessionCommand</a> class for the list of valid commands.
- */
-public final class Session2Command implements Parcelable {
-    /**
-     * Command code for the custom command which can be defined by string action in the
-     * {@link Session2Command}.
-     */
-    public static final int COMMAND_CODE_CUSTOM = 0;
-
-    public static final @android.annotation.NonNull Parcelable.Creator<Session2Command> CREATOR =
-            new Parcelable.Creator<Session2Command>() {
-                @Override
-                public Session2Command createFromParcel(Parcel in) {
-                    return new Session2Command(in);
-                }
-
-                @Override
-                public Session2Command[] newArray(int size) {
-                    return new Session2Command[size];
-                }
-            };
-
-    private final int mCommandCode;
-    // Nonnull if it's custom command
-    private final String mCustomAction;
-    private final Bundle mCustomExtras;
-
-    /**
-     * Constructor for creating a command predefined in AndroidX media2.
-     *
-     * @param commandCode A command code for a command predefined in AndroidX media2.
-     */
-    public Session2Command(int commandCode) {
-        if (commandCode == COMMAND_CODE_CUSTOM) {
-            throw new IllegalArgumentException("commandCode shouldn't be COMMAND_CODE_CUSTOM");
-        }
-        mCommandCode = commandCode;
-        mCustomAction = null;
-        mCustomExtras = null;
-    }
-
-    /**
-     * Constructor for creating a custom command.
-     *
-     * @param action The action of this custom command.
-     * @param extras An extra bundle for this custom command.
-     */
-    public Session2Command(@NonNull String action, @Nullable Bundle extras) {
-        if (action == null) {
-            throw new IllegalArgumentException("action shouldn't be null");
-        }
-        mCommandCode = COMMAND_CODE_CUSTOM;
-        mCustomAction = action;
-        mCustomExtras = extras;
-    }
-
-    /**
-     * Used by parcelable creator.
-     */
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    Session2Command(Parcel in) {
-        mCommandCode = in.readInt();
-        mCustomAction = in.readString();
-        mCustomExtras = in.readBundle();
-    }
-
-    /**
-     * Gets the command code of a predefined command.
-     * This will return {@link #COMMAND_CODE_CUSTOM} for a custom command.
-     */
-    public int getCommandCode() {
-        return mCommandCode;
-    }
-
-    /**
-     * Gets the action of a custom command.
-     * This will return {@code null} for a predefined command.
-     */
-    @Nullable
-    public String getCustomAction() {
-        return mCustomAction;
-    }
-
-    /**
-     * Gets the extra bundle of a custom command.
-     * This will return {@code null} for a predefined command.
-     */
-    @Nullable
-    public Bundle getCustomExtras() {
-        return mCustomExtras;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        if (dest == null) {
-            throw new IllegalArgumentException("parcel shouldn't be null");
-        }
-        dest.writeInt(mCommandCode);
-        dest.writeString(mCustomAction);
-        dest.writeBundle(mCustomExtras);
-    }
-
-    @Override
-    public boolean equals(@Nullable Object obj) {
-        if (!(obj instanceof Session2Command)) {
-            return false;
-        }
-        Session2Command other = (Session2Command) obj;
-        return mCommandCode == other.mCommandCode
-                && TextUtils.equals(mCustomAction, other.mCustomAction);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mCustomAction, mCommandCode);
-    }
-
-    /**
-     * This API is not generally intended for third party application developers.
-     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
-     * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
-     * Library</a> for consistent behavior across all devices.
-     * <p>
-     * Contains the result of {@link Session2Command}.
-     */
-    public static final class Result {
-        private final int mResultCode;
-        private final Bundle mResultData;
-
-        /**
-         * Result code representing that the command is skipped or canceled. For an example, a seek
-         * command can be skipped if it is followed by another seek command.
-         */
-        public static final int RESULT_INFO_SKIPPED = 1;
-
-        /**
-         * Result code representing that the command is successfully completed.
-         */
-        public static final int RESULT_SUCCESS = 0;
-
-        /**
-         * Result code represents that call is ended with an unknown error.
-         */
-        public static final int RESULT_ERROR_UNKNOWN_ERROR = -1;
-
-        /**
-         * Constructor of {@link Result}.
-         *
-         * @param resultCode result code
-         * @param resultData result data
-         */
-        public Result(int resultCode, @Nullable Bundle resultData) {
-            mResultCode = resultCode;
-            mResultData = resultData;
-        }
-
-        /**
-         * Returns the result code.
-         */
-        public int getResultCode() {
-            return mResultCode;
-        }
-
-        /**
-         * Returns the result data.
-         */
-        @Nullable
-        public Bundle getResultData() {
-            return mResultData;
-        }
-    }
-}
diff --git a/apex/media/framework/java/android/media/Session2CommandGroup.java b/apex/media/framework/java/android/media/Session2CommandGroup.java
deleted file mode 100644
index af8184a..0000000
--- a/apex/media/framework/java/android/media/Session2CommandGroup.java
+++ /dev/null
@@ -1,197 +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 android.media;
-
-import static android.media.Session2Command.COMMAND_CODE_CUSTOM;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
- * Library</a> for consistent behavior across all devices.
- * <p>
- * A set of {@link Session2Command} which represents a command group.
- */
-public final class Session2CommandGroup implements Parcelable {
-    private static final String TAG = "Session2CommandGroup";
-
-    public static final @android.annotation.NonNull Parcelable.Creator<Session2CommandGroup>
-            CREATOR = new Parcelable.Creator<Session2CommandGroup>() {
-                @Override
-                public Session2CommandGroup createFromParcel(Parcel in) {
-                    return new Session2CommandGroup(in);
-                }
-
-                @Override
-                public Session2CommandGroup[] newArray(int size) {
-                    return new Session2CommandGroup[size];
-                }
-            };
-
-    Set<Session2Command> mCommands = new HashSet<>();
-
-    /**
-     * Creates a new Session2CommandGroup with commands copied from another object.
-     *
-     * @param commands The collection of commands to copy.
-     */
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    Session2CommandGroup(@Nullable Collection<Session2Command> commands) {
-        if (commands != null) {
-            mCommands.addAll(commands);
-        }
-    }
-
-    /**
-     * Used by parcelable creator.
-     */
-    @SuppressWarnings({"WeakerAccess", "UnsafeParcelApi"}) /* synthetic access */
-    Session2CommandGroup(Parcel in) {
-        Parcelable[] commands = in.readParcelableArray(Session2Command.class.getClassLoader());
-        if (commands != null) {
-            for (Parcelable command : commands) {
-                mCommands.add((Session2Command) command);
-            }
-        }
-    }
-
-    /**
-     * Checks whether this command group has a command that matches given {@code command}.
-     *
-     * @param command A command to find. Shouldn't be {@code null}.
-     */
-    public boolean hasCommand(@NonNull Session2Command command) {
-        if (command == null) {
-            throw new IllegalArgumentException("command shouldn't be null");
-        }
-        return mCommands.contains(command);
-    }
-
-    /**
-     * Checks whether this command group has a command that matches given {@code commandCode}.
-     *
-     * @param commandCode A command code to find.
-     *                    Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
-     */
-    public boolean hasCommand(int commandCode) {
-        if (commandCode == COMMAND_CODE_CUSTOM) {
-            throw new IllegalArgumentException("Use hasCommand(Command) for custom command");
-        }
-        for (Session2Command command : mCommands) {
-            if (command.getCommandCode() == commandCode) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Gets all commands of this command group.
-     */
-    @NonNull
-    public Set<Session2Command> getCommands() {
-        return new HashSet<>(mCommands);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        if (dest == null) {
-            throw new IllegalArgumentException("parcel shouldn't be null");
-        }
-        dest.writeParcelableArray(mCommands.toArray(new Session2Command[0]), 0);
-    }
-
-    /**
-     * This API is not generally intended for third party application developers.
-     * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
-     * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
-     * Library</a> for consistent behavior across all devices.
-     * <p>
-     * Builds a {@link Session2CommandGroup} object.
-     */
-    public static final class Builder {
-        private Set<Session2Command> mCommands;
-
-        public Builder() {
-            mCommands = new HashSet<>();
-        }
-
-        /**
-         * Creates a new builder for {@link Session2CommandGroup} with commands copied from another
-         * {@link Session2CommandGroup} object.
-         * @param commandGroup
-         */
-        public Builder(@NonNull Session2CommandGroup commandGroup) {
-            if (commandGroup == null) {
-                throw new IllegalArgumentException("command group shouldn't be null");
-            }
-            mCommands = commandGroup.getCommands();
-        }
-
-        /**
-         * Adds a command to this command group.
-         *
-         * @param command A command to add. Shouldn't be {@code null}.
-         */
-        @NonNull
-        public Builder addCommand(@NonNull Session2Command command) {
-            if (command == null) {
-                throw new IllegalArgumentException("command shouldn't be null");
-            }
-            mCommands.add(command);
-            return this;
-        }
-
-        /**
-         * Removes a command from this group which matches given {@code command}.
-         *
-         * @param command A command to find. Shouldn't be {@code null}.
-         */
-        @NonNull
-        public Builder removeCommand(@NonNull Session2Command command) {
-            if (command == null) {
-                throw new IllegalArgumentException("command shouldn't be null");
-            }
-            mCommands.remove(command);
-            return this;
-        }
-
-        /**
-         * Builds {@link Session2CommandGroup}.
-         *
-         * @return a new {@link Session2CommandGroup}.
-         */
-        @NonNull
-        public Session2CommandGroup build() {
-            return new Session2CommandGroup(mCommands);
-        }
-    }
-}
diff --git a/apex/media/framework/java/android/media/Session2Link.java b/apex/media/framework/java/android/media/Session2Link.java
deleted file mode 100644
index 6e550e8..0000000
--- a/apex/media/framework/java/android/media/Session2Link.java
+++ /dev/null
@@ -1,226 +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 android.media;
-
-import android.annotation.NonNull;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.util.Log;
-
-import java.util.Objects;
-
-/**
- * Handles incoming commands from {@link MediaController2} to {@link MediaSession2}.
- * @hide
- */
-// @SystemApi
-public final class Session2Link implements Parcelable {
-    private static final String TAG = "Session2Link";
-    private static final boolean DEBUG = MediaSession2.DEBUG;
-
-    public static final @android.annotation.NonNull Parcelable.Creator<Session2Link> CREATOR =
-            new Parcelable.Creator<Session2Link>() {
-                @Override
-                public Session2Link createFromParcel(Parcel in) {
-                    return new Session2Link(in);
-                }
-
-                @Override
-                public Session2Link[] newArray(int size) {
-                    return new Session2Link[size];
-                }
-            };
-
-    private final MediaSession2 mSession;
-    private final IMediaSession2 mISession;
-
-    public Session2Link(MediaSession2 session) {
-        mSession = session;
-        mISession = new Session2Stub();
-    }
-
-    Session2Link(Parcel in) {
-        mSession = null;
-        mISession = IMediaSession2.Stub.asInterface(in.readStrongBinder());
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStrongBinder(mISession.asBinder());
-    }
-
-    @Override
-    public int hashCode() {
-        return mISession.asBinder().hashCode();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof Session2Link)) {
-            return false;
-        }
-        Session2Link other = (Session2Link) obj;
-        return Objects.equals(mISession.asBinder(), other.mISession.asBinder());
-    }
-
-    /** Link to death with mISession */
-    public void linkToDeath(@NonNull IBinder.DeathRecipient recipient, int flags) {
-        if (mISession != null) {
-            try {
-                mISession.asBinder().linkToDeath(recipient, flags);
-            } catch (RemoteException e) {
-                if (DEBUG) {
-                    Log.d(TAG, "Session died too early.", e);
-                }
-            }
-        }
-    }
-
-    /** Unlink to death with mISession */
-    public boolean unlinkToDeath(@NonNull IBinder.DeathRecipient recipient, int flags) {
-        if (mISession != null) {
-            return mISession.asBinder().unlinkToDeath(recipient, flags);
-        }
-        return true;
-    }
-
-    /** Interface method for IMediaSession2.connect */
-    public void connect(final Controller2Link caller, int seq, Bundle connectionRequest) {
-        try {
-            mISession.connect(caller, seq, connectionRequest);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for IMediaSession2.disconnect */
-    public void disconnect(final Controller2Link caller, int seq) {
-        try {
-            mISession.disconnect(caller, seq);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for IMediaSession2.sendSessionCommand */
-    public void sendSessionCommand(final Controller2Link caller, final int seq,
-            final Session2Command command, final Bundle args, ResultReceiver resultReceiver) {
-        try {
-            mISession.sendSessionCommand(caller, seq, command, args, resultReceiver);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Interface method for IMediaSession2.sendSessionCommand */
-    public void cancelSessionCommand(final Controller2Link caller, final int seq) {
-        try {
-            mISession.cancelSessionCommand(caller, seq);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Stub implementation for IMediaSession2.connect */
-    public void onConnect(final Controller2Link caller, int pid, int uid, int seq,
-            Bundle connectionRequest) {
-        mSession.onConnect(caller, pid, uid, seq, connectionRequest);
-    }
-
-    /** Stub implementation for IMediaSession2.disconnect */
-    public void onDisconnect(final Controller2Link caller, int seq) {
-        mSession.onDisconnect(caller, seq);
-    }
-
-    /** Stub implementation for IMediaSession2.sendSessionCommand */
-    public void onSessionCommand(final Controller2Link caller, final int seq,
-            final Session2Command command, final Bundle args, ResultReceiver resultReceiver) {
-        mSession.onSessionCommand(caller, seq, command, args, resultReceiver);
-    }
-
-    /** Stub implementation for IMediaSession2.cancelSessionCommand */
-    public void onCancelCommand(final Controller2Link caller, final int seq) {
-        mSession.onCancelCommand(caller, seq);
-    }
-
-    private class Session2Stub extends IMediaSession2.Stub {
-        @Override
-        public void connect(final Controller2Link caller, int seq, Bundle connectionRequest) {
-            if (caller == null || connectionRequest == null) {
-                return;
-            }
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                Session2Link.this.onConnect(caller, pid, uid, seq, connectionRequest);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void disconnect(final Controller2Link caller, int seq) {
-            if (caller == null) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                Session2Link.this.onDisconnect(caller, seq);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void sendSessionCommand(final Controller2Link caller, final int seq,
-                final Session2Command command, final Bundle args, ResultReceiver resultReceiver) {
-            if (caller == null) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                Session2Link.this.onSessionCommand(caller, seq, command, args, resultReceiver);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void cancelSessionCommand(final Controller2Link caller, final int seq) {
-            if (caller == null) {
-                return;
-            }
-            final long token = Binder.clearCallingIdentity();
-            try {
-                Session2Link.this.onCancelCommand(caller, seq);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-    }
-}
diff --git a/apex/media/framework/java/android/media/Session2Token.java b/apex/media/framework/java/android/media/Session2Token.java
deleted file mode 100644
index aae2e1b..0000000
--- a/apex/media/framework/java/android/media/Session2Token.java
+++ /dev/null
@@ -1,272 +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 android.media;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
- * Library</a> for consistent behavior across all devices.
- * <p>
- * Represents an ongoing {@link MediaSession2} or a {@link MediaSession2Service}.
- * If it's representing a session service, it may not be ongoing.
- * <p>
- * This may be passed to apps by the session owner to allow them to create a
- * {@link MediaController2} to communicate with the session.
- * <p>
- * It can be also obtained by {@link android.media.session.MediaSessionManager}.
- */
-public final class Session2Token implements Parcelable {
-    private static final String TAG = "Session2Token";
-
-    public static final @android.annotation.NonNull Creator<Session2Token> CREATOR =
-            new Creator<Session2Token>() {
-                @Override
-                public Session2Token createFromParcel(Parcel p) {
-                    return new Session2Token(p);
-                }
-
-                @Override
-                public Session2Token[] newArray(int size) {
-                    return new Session2Token[size];
-                }
-            };
-
-    /**
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "TYPE_", value = {TYPE_SESSION, TYPE_SESSION_SERVICE})
-    public @interface TokenType {
-    }
-
-    /**
-     * Type for {@link MediaSession2}.
-     */
-    public static final int TYPE_SESSION = 0;
-
-    /**
-     * Type for {@link MediaSession2Service}.
-     */
-    public static final int TYPE_SESSION_SERVICE = 1;
-
-    private final int mUid;
-    @TokenType
-    private final int mType;
-    private final String mPackageName;
-    private final String mServiceName;
-    private final Session2Link mSessionLink;
-    private final ComponentName mComponentName;
-    private final Bundle mExtras;
-
-    /**
-     * Constructor for the token with type {@link #TYPE_SESSION_SERVICE}.
-     *
-     * @param context The context.
-     * @param serviceComponent The component name of the service.
-     */
-    public Session2Token(@NonNull Context context, @NonNull ComponentName serviceComponent) {
-        if (context == null) {
-            throw new IllegalArgumentException("context shouldn't be null");
-        }
-        if (serviceComponent == null) {
-            throw new IllegalArgumentException("serviceComponent shouldn't be null");
-        }
-
-        final PackageManager manager = context.getPackageManager();
-        final int uid = getUid(manager, serviceComponent.getPackageName());
-
-        if (!isInterfaceDeclared(manager, MediaSession2Service.SERVICE_INTERFACE,
-                serviceComponent)) {
-            Log.w(TAG, serviceComponent + " doesn't implement MediaSession2Service.");
-        }
-        mComponentName = serviceComponent;
-        mPackageName = serviceComponent.getPackageName();
-        mServiceName = serviceComponent.getClassName();
-        mUid = uid;
-        mType = TYPE_SESSION_SERVICE;
-        mSessionLink = null;
-        mExtras = Bundle.EMPTY;
-    }
-
-    Session2Token(int uid, int type, String packageName, Session2Link sessionLink,
-            @NonNull Bundle tokenExtras) {
-        mUid = uid;
-        mType = type;
-        mPackageName = packageName;
-        mServiceName = null;
-        mComponentName = null;
-        mSessionLink = sessionLink;
-        mExtras = tokenExtras;
-    }
-
-    Session2Token(Parcel in) {
-        mUid = in.readInt();
-        mType = in.readInt();
-        mPackageName = in.readString();
-        mServiceName = in.readString();
-        mSessionLink = in.readParcelable(null);
-        mComponentName = ComponentName.unflattenFromString(in.readString());
-
-        Bundle extras = in.readBundle();
-        if (extras == null) {
-            Log.w(TAG, "extras shouldn't be null.");
-            extras = Bundle.EMPTY;
-        } else if (MediaSession2.hasCustomParcelable(extras)) {
-            Log.w(TAG, "extras contain custom parcelable. Ignoring.");
-            extras = Bundle.EMPTY;
-        }
-        mExtras = extras;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mUid);
-        dest.writeInt(mType);
-        dest.writeString(mPackageName);
-        dest.writeString(mServiceName);
-        dest.writeParcelable(mSessionLink, flags);
-        dest.writeString(mComponentName == null ? "" : mComponentName.flattenToString());
-        dest.writeBundle(mExtras);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mType, mUid, mPackageName, mServiceName, mSessionLink);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof Session2Token)) {
-            return false;
-        }
-        Session2Token other = (Session2Token) obj;
-        return mUid == other.mUid
-                && TextUtils.equals(mPackageName, other.mPackageName)
-                && TextUtils.equals(mServiceName, other.mServiceName)
-                && mType == other.mType
-                && Objects.equals(mSessionLink, other.mSessionLink);
-    }
-
-    @Override
-    public String toString() {
-        return "Session2Token {pkg=" + mPackageName + " type=" + mType
-                + " service=" + mServiceName + " Session2Link=" + mSessionLink + "}";
-    }
-
-    /**
-     * @return uid of the session
-     */
-    public int getUid() {
-        return mUid;
-    }
-
-    /**
-     * @return package name of the session
-     */
-    @NonNull
-    public String getPackageName() {
-        return mPackageName;
-    }
-
-    /**
-     * @return service name of the session. Can be {@code null} for {@link #TYPE_SESSION}.
-     */
-    @Nullable
-    public String getServiceName() {
-        return mServiceName;
-    }
-
-    /**
-     * @return type of the token
-     * @see #TYPE_SESSION
-     * @see #TYPE_SESSION_SERVICE
-     */
-    public @TokenType int getType() {
-        return mType;
-    }
-
-    /**
-     * @return extras of the token
-     * @see MediaSession2.Builder#setExtras(Bundle)
-     */
-    @NonNull
-    public Bundle getExtras() {
-        return new Bundle(mExtras);
-    }
-
-    Session2Link getSessionLink() {
-        return mSessionLink;
-    }
-
-    private static boolean isInterfaceDeclared(PackageManager manager, String serviceInterface,
-            ComponentName serviceComponent) {
-        Intent serviceIntent = new Intent(serviceInterface);
-        // Use queryIntentServices to find services with MediaSession2Service.SERVICE_INTERFACE.
-        // We cannot use resolveService with intent specified class name, because resolveService
-        // ignores actions if Intent.setClassName() is specified.
-        serviceIntent.setPackage(serviceComponent.getPackageName());
-
-        List<ResolveInfo> list = manager.queryIntentServices(
-                serviceIntent, PackageManager.GET_META_DATA);
-        if (list != null) {
-            for (int i = 0; i < list.size(); i++) {
-                ResolveInfo resolveInfo = list.get(i);
-                if (resolveInfo == null || resolveInfo.serviceInfo == null) {
-                    continue;
-                }
-                if (TextUtils.equals(
-                        resolveInfo.serviceInfo.name, serviceComponent.getClassName())) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private static int getUid(PackageManager manager, String packageName) {
-        try {
-            return manager.getApplicationInfo(packageName, 0).uid;
-        } catch (PackageManager.NameNotFoundException e) {
-            throw new IllegalArgumentException("Cannot find package " + packageName);
-        }
-    }
-}
diff --git a/apex/media/framework/jni/android_media_MediaParserJNI.cpp b/apex/media/framework/jni/android_media_MediaParserJNI.cpp
deleted file mode 100644
index c81152c..0000000
--- a/apex/media/framework/jni/android_media_MediaParserJNI.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2020, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <jni.h>
-#include <media/MediaMetrics.h>
-
-#define JNI_FUNCTION(RETURN_TYPE, NAME, ...)                                               \
-    extern "C" {                                                                           \
-    JNIEXPORT RETURN_TYPE Java_android_media_MediaParser_##NAME(JNIEnv* env, jobject thiz, \
-                                                                ##__VA_ARGS__);            \
-    }                                                                                      \
-    JNIEXPORT RETURN_TYPE Java_android_media_MediaParser_##NAME(JNIEnv* env, jobject thiz, \
-                                                                ##__VA_ARGS__)
-
-namespace {
-
-constexpr char kMediaMetricsKey[] = "mediaparser";
-
-constexpr char kAttributeLogSessionId[] = "android.media.mediaparser.logSessionId";
-constexpr char kAttributeParserName[] = "android.media.mediaparser.parserName";
-constexpr char kAttributeCreatedByName[] = "android.media.mediaparser.createdByName";
-constexpr char kAttributeParserPool[] = "android.media.mediaparser.parserPool";
-constexpr char kAttributeLastException[] = "android.media.mediaparser.lastException";
-constexpr char kAttributeResourceByteCount[] = "android.media.mediaparser.resourceByteCount";
-constexpr char kAttributeDurationMillis[] = "android.media.mediaparser.durationMillis";
-constexpr char kAttributeTrackMimeTypes[] = "android.media.mediaparser.trackMimeTypes";
-constexpr char kAttributeTrackCodecs[] = "android.media.mediaparser.trackCodecs";
-constexpr char kAttributeAlteredParameters[] = "android.media.mediaparser.alteredParameters";
-constexpr char kAttributeVideoWidth[] = "android.media.mediaparser.videoWidth";
-constexpr char kAttributeVideoHeight[] = "android.media.mediaparser.videoHeight";
-
-// Util class to handle string resource management.
-class JstringHandle {
-public:
-    JstringHandle(JNIEnv* env, jstring value) : mEnv(env), mJstringValue(value) {
-        mCstringValue = env->GetStringUTFChars(value, /* isCopy= */ nullptr);
-    }
-
-    ~JstringHandle() {
-        if (mCstringValue != nullptr) {
-            mEnv->ReleaseStringUTFChars(mJstringValue, mCstringValue);
-        }
-    }
-
-    [[nodiscard]] const char* value() const {
-        return mCstringValue != nullptr ? mCstringValue : "";
-    }
-
-    JNIEnv* mEnv;
-    jstring mJstringValue;
-    const char* mCstringValue;
-};
-
-} // namespace
-
-JNI_FUNCTION(void, nativeSubmitMetrics, jstring logSessionIdJstring, jstring parserNameJstring,
-             jboolean createdByName, jstring parserPoolJstring, jstring lastExceptionJstring,
-             jlong resourceByteCount, jlong durationMillis, jstring trackMimeTypesJstring,
-             jstring trackCodecsJstring, jstring alteredParameters, jint videoWidth,
-             jint videoHeight) {
-    mediametrics_handle_t item(mediametrics_create(kMediaMetricsKey));
-    mediametrics_setCString(item, kAttributeLogSessionId,
-                            JstringHandle(env, logSessionIdJstring).value());
-    mediametrics_setCString(item, kAttributeParserName,
-                            JstringHandle(env, parserNameJstring).value());
-    mediametrics_setInt32(item, kAttributeCreatedByName, createdByName ? 1 : 0);
-    mediametrics_setCString(item, kAttributeParserPool,
-                            JstringHandle(env, parserPoolJstring).value());
-    mediametrics_setCString(item, kAttributeLastException,
-                            JstringHandle(env, lastExceptionJstring).value());
-    mediametrics_setInt64(item, kAttributeResourceByteCount, resourceByteCount);
-    mediametrics_setInt64(item, kAttributeDurationMillis, durationMillis);
-    mediametrics_setCString(item, kAttributeTrackMimeTypes,
-                            JstringHandle(env, trackMimeTypesJstring).value());
-    mediametrics_setCString(item, kAttributeTrackCodecs,
-                            JstringHandle(env, trackCodecsJstring).value());
-    mediametrics_setCString(item, kAttributeAlteredParameters,
-                            JstringHandle(env, alteredParameters).value());
-    mediametrics_setInt32(item, kAttributeVideoWidth, videoWidth);
-    mediametrics_setInt32(item, kAttributeVideoHeight, videoHeight);
-    mediametrics_selfRecord(item);
-    mediametrics_delete(item);
-}
diff --git a/apex/media/framework/lint-baseline.xml b/apex/media/framework/lint-baseline.xml
deleted file mode 100644
index 95eea45..0000000
--- a/apex/media/framework/lint-baseline.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.2.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.2.0-dev">
-
-    <issue
-        id="DefaultLocale"
-        message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
-        errorLine1="        if (mSupportedVideoMimeTypes.contains(videoMime.toLowerCase())) {"
-        errorLine2="                                                        ~~~~~~~~~~~">
-        <location
-            file="frameworks/base/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java"
-            line="121"
-            column="57"/>
-    </issue>
-
-    <issue
-        id="DefaultLocale"
-        message="Implicitly using the default locale is a common source of bugs: Use `String.format(Locale, ...)` instead"
-        errorLine1="            return String.format(&quot; session: {id: %d, status: %s, result: %s, progress: %d}&quot;,"
-        errorLine2="                   ^">
-        <location
-            file="frameworks/base/apex/media/framework/java/android/media/MediaTranscodingManager.java"
-            line="1651"
-            column="20"/>
-    </issue>
-
-    <issue
-        id="ParcelClassLoader"
-        message="Passing null here (to use the default class loader) will not work if you are restoring your own classes. Consider using for example `getClass().getClassLoader()` instead."
-        errorLine1="            Bundle out = parcel.readBundle(null);"
-        errorLine2="                                ~~~~~~~~~~~~~~~~">
-        <location
-            file="frameworks/base/apex/media/framework/java/android/media/MediaSession2.java"
-            line="303"
-            column="33"/>
-    </issue>
-
-    <issue
-        id="ParcelClassLoader"
-        message="Using the default class loader will not work if you are restoring your own classes. Consider using for example `readBundle(getClass().getClassLoader())` instead."
-        errorLine1="        mCustomExtras = in.readBundle();"
-        errorLine2="                           ~~~~~~~~~~~~">
-        <location
-            file="frameworks/base/apex/media/framework/java/android/media/Session2Command.java"
-            line="104"
-            column="28"/>
-    </issue>
-
-    <issue
-        id="ParcelClassLoader"
-        message="Passing null here (to use the default class loader) will not work if you are restoring your own classes. Consider using for example `getClass().getClassLoader()` instead."
-        errorLine1="        mSessionLink = in.readParcelable(null);"
-        errorLine2="                          ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="frameworks/base/apex/media/framework/java/android/media/Session2Token.java"
-            line="141"
-            column="27"/>
-    </issue>
-
-    <issue
-        id="ParcelClassLoader"
-        message="Using the default class loader will not work if you are restoring your own classes. Consider using for example `readBundle(getClass().getClassLoader())` instead."
-        errorLine1="        Bundle extras = in.readBundle();"
-        errorLine2="                           ~~~~~~~~~~~~">
-        <location
-            file="frameworks/base/apex/media/framework/java/android/media/Session2Token.java"
-            line="144"
-            column="28"/>
-    </issue>
-
-</issues>
diff --git a/apex/media/framework/updatable-media-proguard.flags b/apex/media/framework/updatable-media-proguard.flags
deleted file mode 100644
index 4e7d842..0000000
--- a/apex/media/framework/updatable-media-proguard.flags
+++ /dev/null
@@ -1,2 +0,0 @@
-# Keep all symbols in android.media.
--keep class android.media.* {*;}
diff --git a/apex/media/service/Android.bp b/apex/media/service/Android.bp
deleted file mode 100644
index 0e300bb..0000000
--- a/apex/media/service/Android.bp
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2020 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 {
-    // See: http://go/android-license-faq
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-filegroup {
-    name: "service-media-s-sources",
-    srcs: [
-        "java/**/*.java",
-    ],
-    path: "java",
-    visibility: ["//visibility:private"],
-}
-
-java_sdk_library {
-    name: "service-media-s",
-    permitted_packages: [
-        "com.android.server.media",
-    ],
-    defaults: ["framework-system-server-module-defaults"],
-    srcs: [
-        ":service-media-s-sources",
-    ],
-    libs: [
-        "androidx.annotation_annotation",
-        "updatable-media",
-        "modules-annotation-minsdk",
-        "modules-utils-build",
-    ],
-    jarjar_rules: "jarjar_rules.txt",
-    sdk_version: "system_server_current",
-    min_sdk_version: "29", // TODO: We may need to bump this at some point.
-    lint: {
-        strict_updatability_linting: true,
-    },
-    apex_available: [
-        "com.android.media",
-    ],
-}
diff --git a/apex/media/service/api/current.txt b/apex/media/service/api/current.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/media/service/api/current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/media/service/api/removed.txt b/apex/media/service/api/removed.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/media/service/api/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/media/service/api/system-server-current.txt b/apex/media/service/api/system-server-current.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/media/service/api/system-server-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/media/service/api/system-server-removed.txt b/apex/media/service/api/system-server-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/media/service/api/system-server-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/media/service/jarjar_rules.txt b/apex/media/service/jarjar_rules.txt
deleted file mode 100644
index 7e37c2b..0000000
--- a/apex/media/service/jarjar_rules.txt
+++ /dev/null
@@ -1 +0,0 @@
-rule com.android.modules.** android.media.internal.@1
diff --git a/apex/media/service/java/com/android/server/media/MediaCommunicationService.java b/apex/media/service/java/com/android/server/media/MediaCommunicationService.java
deleted file mode 100644
index 4223fa6..0000000
--- a/apex/media/service/java/com/android/server/media/MediaCommunicationService.java
+++ /dev/null
@@ -1,685 +0,0 @@
-/*
- * Copyright 2020 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.server.media;
-
-import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.os.UserHandle.ALL;
-import static android.os.UserHandle.getUserHandleForUid;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.media.IMediaCommunicationService;
-import android.media.IMediaCommunicationServiceCallback;
-import android.media.MediaController2;
-import android.media.MediaParceledListSlice;
-import android.media.Session2CommandGroup;
-import android.media.Session2Token;
-import android.media.session.MediaSessionManager;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.view.KeyEvent;
-
-import androidx.annotation.RequiresApi;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.modules.annotation.MinSdk;
-import com.android.server.SystemService;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-
-/**
- * A system service that manages {@link android.media.MediaSession2} creations
- * and their ongoing media playback state.
- * @hide
- */
-@MinSdk(Build.VERSION_CODES.S)
-@RequiresApi(Build.VERSION_CODES.S)
-public class MediaCommunicationService extends SystemService {
-    private static final String TAG = "MediaCommunicationSrv";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    final Context mContext;
-
-    final Object mLock = new Object();
-    final Handler mHandler = new Handler(Looper.getMainLooper());
-
-    @GuardedBy("mLock")
-    private final SparseIntArray mFullUserIds = new SparseIntArray();
-    @GuardedBy("mLock")
-    private final SparseArray<FullUserRecord> mUserRecords = new SparseArray<>();
-
-    final Executor mRecordExecutor = Executors.newSingleThreadExecutor();
-    @GuardedBy("mLock")
-    final ArrayList<CallbackRecord> mCallbackRecords = new ArrayList<>();
-    final NotificationManager mNotificationManager;
-    MediaSessionManager mSessionManager;
-
-    public MediaCommunicationService(Context context) {
-        super(context);
-        mContext = context;
-        mNotificationManager = context.getSystemService(NotificationManager.class);
-    }
-
-    @Override
-    public void onStart() {
-        publishBinderService(Context.MEDIA_COMMUNICATION_SERVICE, new Stub());
-        updateUser();
-    }
-
-    @Override
-    public void onBootPhase(int phase) {
-        super.onBootPhase(phase);
-        switch (phase) {
-            // This ensures MediaSessionService is started
-            case PHASE_BOOT_COMPLETED:
-                mSessionManager = mContext.getSystemService(MediaSessionManager.class);
-                break;
-        }
-    }
-
-    @Override
-    public void onUserStarting(@NonNull TargetUser user) {
-        if (DEBUG) Log.d(TAG, "onUserStarting: " + user);
-        updateUser();
-    }
-
-    @Override
-    public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
-        if (DEBUG) Log.d(TAG, "onUserSwitching: " + to);
-        updateUser();
-    }
-
-    @Override
-    public void onUserStopped(@NonNull TargetUser targetUser) {
-        int userId = targetUser.getUserHandle().getIdentifier();
-
-        if (DEBUG) Log.d(TAG, "onUserStopped: " + userId);
-        synchronized (mLock) {
-            FullUserRecord user = getFullUserRecordLocked(userId);
-            if (user != null) {
-                if (user.getFullUserId() == userId) {
-                    user.destroyAllSessions();
-                    mUserRecords.remove(userId);
-                } else {
-                    user.destroySessionsForUser(userId);
-                }
-            }
-        }
-        updateUser();
-    }
-
-    @Nullable
-    CallbackRecord findCallbackRecordLocked(@Nullable IMediaCommunicationServiceCallback callback) {
-        if (callback == null) {
-            return null;
-        }
-        for (CallbackRecord record : mCallbackRecords) {
-            if (Objects.equals(callback.asBinder(), record.mCallback.asBinder())) {
-                return record;
-            }
-        }
-        return null;
-    }
-
-    ArrayList<Session2Token> getSession2TokensLocked(int userId) {
-        ArrayList<Session2Token> list = new ArrayList<>();
-        if (userId == ALL.getIdentifier()) {
-            int size = mUserRecords.size();
-            for (int i = 0; i < size; i++) {
-                list.addAll(mUserRecords.valueAt(i).getAllSession2Tokens());
-            }
-        } else {
-            FullUserRecord user = getFullUserRecordLocked(userId);
-            if (user != null) {
-                list.addAll(user.getSession2Tokens(userId));
-            }
-        }
-        return list;
-    }
-
-    private FullUserRecord getFullUserRecordLocked(int userId) {
-        int fullUserId = mFullUserIds.get(userId, -1);
-        if (fullUserId < 0) {
-            return null;
-        }
-        return mUserRecords.get(fullUserId);
-    }
-
-    private boolean hasMediaControlPermission(int pid, int uid) {
-        // Check if it's system server or has MEDIA_CONTENT_CONTROL.
-        // Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
-        // check here.
-        if (uid == Process.SYSTEM_UID || mContext.checkPermission(
-                android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
-                == PackageManager.PERMISSION_GRANTED) {
-            return true;
-        } else if (DEBUG) {
-            Log.d(TAG, "uid(" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
-        }
-        return false;
-    }
-
-    private void updateUser() {
-        UserManager manager = mContext.getSystemService(UserManager.class);
-        List<UserHandle> allUsers = manager.getUserHandles(/*excludeDying=*/false);
-
-        synchronized (mLock) {
-            mFullUserIds.clear();
-            if (allUsers != null) {
-                for (UserHandle user : allUsers) {
-                    UserHandle parent = manager.getProfileParent(user);
-                    if (parent != null) {
-                        mFullUserIds.put(user.getIdentifier(), parent.getIdentifier());
-                    } else {
-                        mFullUserIds.put(user.getIdentifier(), user.getIdentifier());
-                        if (mUserRecords.get(user.getIdentifier()) == null) {
-                            mUserRecords.put(user.getIdentifier(),
-                                    new FullUserRecord(user.getIdentifier()));
-                        }
-                    }
-                }
-            }
-            // Ensure that the current full user exists.
-            int currentFullUserId = ActivityManager.getCurrentUser();
-            FullUserRecord currentFullUserRecord = mUserRecords.get(currentFullUserId);
-            if (currentFullUserRecord == null) {
-                Log.w(TAG, "Cannot find FullUserInfo for the current user " + currentFullUserId);
-                currentFullUserRecord = new FullUserRecord(currentFullUserId);
-                mUserRecords.put(currentFullUserId, currentFullUserRecord);
-            }
-            mFullUserIds.put(currentFullUserId, currentFullUserId);
-        }
-    }
-
-    void dispatchSession2Created(Session2Token token) {
-        synchronized (mLock) {
-            for (CallbackRecord record : mCallbackRecords) {
-                if (record.mUserId != ALL.getIdentifier()
-                        && record.mUserId != getUserHandleForUid(token.getUid()).getIdentifier()) {
-                    continue;
-                }
-                try {
-                    record.mCallback.onSession2Created(token);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Failed to notify session2 token created " + record);
-                }
-            }
-        }
-    }
-
-    void dispatchSession2Changed(int userId) {
-        ArrayList<Session2Token> allSession2Tokens;
-        ArrayList<Session2Token> userSession2Tokens;
-
-        synchronized (mLock) {
-            allSession2Tokens = getSession2TokensLocked(ALL.getIdentifier());
-            userSession2Tokens = getSession2TokensLocked(userId);
-
-            for (CallbackRecord record : mCallbackRecords) {
-                if (record.mUserId == ALL.getIdentifier()) {
-                    try {
-                        MediaParceledListSlice<Session2Token> toSend =
-                                new MediaParceledListSlice<>(allSession2Tokens);
-                        toSend.setInlineCountLimit(0);
-                        record.mCallback.onSession2Changed(toSend);
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Failed to notify session2 tokens changed " + record);
-                    }
-                } else if (record.mUserId == userId) {
-                    try {
-                        MediaParceledListSlice<Session2Token> toSend =
-                                new MediaParceledListSlice<>(userSession2Tokens);
-                        toSend.setInlineCountLimit(0);
-                        record.mCallback.onSession2Changed(toSend);
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Failed to notify session2 tokens changed " + record);
-                    }
-                }
-            }
-        }
-    }
-
-    void onSessionDied(Session2Record session) {
-        if (DEBUG) {
-            Log.d(TAG, "Destroying " + session);
-        }
-        if (session.isClosed()) {
-            Log.w(TAG, "Destroying already destroyed session. Ignoring.");
-            return;
-        }
-
-        FullUserRecord user = session.getFullUser();
-        if (user != null) {
-            user.removeSession(session);
-        }
-        session.close();
-    }
-
-    void onSessionPlaybackStateChanged(Session2Record session, boolean promotePriority) {
-        FullUserRecord user = session.getFullUser();
-        if (user == null || !user.containsSession(session)) {
-            Log.d(TAG, "Unknown session changed playback state. Ignoring.");
-            return;
-        }
-        user.onPlaybackStateChanged(session, promotePriority);
-    }
-
-
-    static boolean isMediaSessionKey(int keyCode) {
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_MEDIA_PLAY:
-            case KeyEvent.KEYCODE_MEDIA_PAUSE:
-            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-            case KeyEvent.KEYCODE_MUTE:
-            case KeyEvent.KEYCODE_HEADSETHOOK:
-            case KeyEvent.KEYCODE_MEDIA_STOP:
-            case KeyEvent.KEYCODE_MEDIA_NEXT:
-            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-            case KeyEvent.KEYCODE_MEDIA_REWIND:
-            case KeyEvent.KEYCODE_MEDIA_RECORD:
-            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
-                return true;
-        }
-        return false;
-    }
-
-    private class Stub extends IMediaCommunicationService.Stub {
-        @Override
-        public void notifySession2Created(Session2Token sessionToken) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-
-            try {
-                if (DEBUG) {
-                    Log.d(TAG, "Session2 is created " + sessionToken);
-                }
-                if (uid != sessionToken.getUid()) {
-                    throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid
-                            + " but actually=" + sessionToken.getUid());
-                }
-                FullUserRecord user;
-                int userId = getUserHandleForUid(sessionToken.getUid()).getIdentifier();
-                synchronized (mLock) {
-                    user = getFullUserRecordLocked(userId);
-                }
-                if (user == null) {
-                    Log.w(TAG, "notifySession2Created: Ignore session of an unknown user");
-                    return;
-                }
-                user.addSession(new Session2Record(MediaCommunicationService.this,
-                        user, sessionToken, mRecordExecutor));
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        /**
-         * Returns if the controller's package is trusted (i.e. has either MEDIA_CONTENT_CONTROL
-         * permission or an enabled notification listener)
-         *
-         * @param controllerPackageName package name of the controller app
-         * @param controllerPid pid of the controller app
-         * @param controllerUid uid of the controller app
-         */
-        @Override
-        public boolean isTrusted(String controllerPackageName, int controllerPid,
-                int controllerUid) {
-            final int uid = Binder.getCallingUid();
-            final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                // Don't perform check between controllerPackageName and controllerUid.
-                // When an (activity|service) runs on the another apps process by specifying
-                // android:process in the AndroidManifest.xml, then PID and UID would have the
-                // running process' information instead of the (activity|service) that has created
-                // MediaController.
-                // Note that we can use Context#getOpPackageName() instead of
-                // Context#getPackageName() for getting package name that matches with the PID/UID,
-                // but it doesn't tell which package has created the MediaController, so useless.
-                return hasMediaControlPermission(controllerPid, controllerUid)
-                        || hasEnabledNotificationListener(
-                        userId, controllerPackageName, controllerUid);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public MediaParceledListSlice getSession2Tokens(int userId) {
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-
-            try {
-                // Check that they can make calls on behalf of the user and get the final user id
-                int resolvedUserId = handleIncomingUser(pid, uid, userId, null);
-                ArrayList<Session2Token> result;
-                synchronized (mLock) {
-                    result = getSession2TokensLocked(resolvedUserId);
-                }
-                MediaParceledListSlice parceledListSlice = new MediaParceledListSlice<>(result);
-                parceledListSlice.setInlineCountLimit(1);
-                return parceledListSlice;
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void dispatchMediaKeyEvent(String packageName, KeyEvent keyEvent,
-                boolean asSystemService) {
-            if (keyEvent == null || !isMediaSessionKey(keyEvent.getKeyCode())) {
-                Log.w(TAG, "Attempted to dispatch null or non-media key event.");
-                return;
-            }
-
-            final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                //TODO: Dispatch key event to media session 2 if required
-                mSessionManager.dispatchMediaKeyEvent(keyEvent, asSystemService);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override
-        public void registerCallback(IMediaCommunicationServiceCallback callback,
-                String packageName) throws RemoteException {
-            Objects.requireNonNull(callback, "callback should not be null");
-            Objects.requireNonNull(packageName, "packageName should not be null");
-
-            synchronized (mLock) {
-                if (findCallbackRecordLocked(callback) == null) {
-
-                    CallbackRecord record = new CallbackRecord(callback, packageName,
-                            Binder.getCallingUid(), Binder.getCallingPid());
-                    mCallbackRecords.add(record);
-                    try {
-                        callback.asBinder().linkToDeath(record, 0);
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Failed to register callback", e);
-                        mCallbackRecords.remove(record);
-                    }
-                } else {
-                    Log.e(TAG, "registerCallback is called with already registered callback. "
-                            + "packageName=" + packageName);
-                }
-            }
-        }
-
-        @Override
-        public void unregisterCallback(IMediaCommunicationServiceCallback callback)
-                throws RemoteException {
-            synchronized (mLock) {
-                CallbackRecord existingRecord = findCallbackRecordLocked(callback);
-                if (existingRecord != null) {
-                    mCallbackRecords.remove(existingRecord);
-                    callback.asBinder().unlinkToDeath(existingRecord, 0);
-                } else {
-                    Log.e(TAG, "unregisterCallback is called with unregistered callback.");
-                }
-            }
-        }
-
-        private boolean hasEnabledNotificationListener(int callingUserId,
-                String controllerPackageName, int controllerUid) {
-            int controllerUserId = UserHandle.getUserHandleForUid(controllerUid).getIdentifier();
-            if (callingUserId != controllerUserId) {
-                // Enabled notification listener only works within the same user.
-                return false;
-            }
-
-            if (mNotificationManager.hasEnabledNotificationListener(controllerPackageName,
-                    UserHandle.getUserHandleForUid(controllerUid))) {
-                return true;
-            }
-            if (DEBUG) {
-                Log.d(TAG, controllerPackageName + " (uid=" + controllerUid
-                        + ") doesn't have an enabled notification listener");
-            }
-            return false;
-        }
-
-        // Handles incoming user by checking whether the caller has permission to access the
-        // given user id's information or not. Permission is not necessary if the given user id is
-        // equal to the caller's user id, but if not, the caller needs to have the
-        // INTERACT_ACROSS_USERS_FULL permission. Otherwise, a security exception will be thrown.
-        // The return value will be the given user id, unless the given user id is
-        // UserHandle.CURRENT, which will return the ActivityManager.getCurrentUser() value instead.
-        private int handleIncomingUser(int pid, int uid, int userId, String packageName) {
-            int callingUserId = UserHandle.getUserHandleForUid(uid).getIdentifier();
-            if (userId == callingUserId) {
-                return userId;
-            }
-
-            boolean canInteractAcrossUsersFull = mContext.checkPermission(
-                    INTERACT_ACROSS_USERS_FULL, pid, uid) == PackageManager.PERMISSION_GRANTED;
-            if (canInteractAcrossUsersFull) {
-                if (userId == UserHandle.CURRENT.getIdentifier()) {
-                    return ActivityManager.getCurrentUser();
-                }
-                return userId;
-            }
-
-            throw new SecurityException("Permission denied while calling from " + packageName
-                    + " with user id: " + userId + "; Need to run as either the calling user id ("
-                    + callingUserId + "), or with " + INTERACT_ACROSS_USERS_FULL + " permission");
-        }
-    }
-
-    final class CallbackRecord implements IBinder.DeathRecipient {
-        private final IMediaCommunicationServiceCallback mCallback;
-        private final String mPackageName;
-        private final int mUid;
-        private int mPid;
-        private final int mUserId;
-
-        CallbackRecord(IMediaCommunicationServiceCallback callback,
-                String packageName, int uid, int pid) {
-            mCallback = callback;
-            mPackageName = packageName;
-            mUid = uid;
-            mPid = pid;
-            mUserId = (mContext.checkPermission(
-                    INTERACT_ACROSS_USERS_FULL, pid, uid) == PackageManager.PERMISSION_GRANTED)
-                    ? ALL.getIdentifier() : UserHandle.getUserHandleForUid(mUid).getIdentifier();
-        }
-
-        @Override
-        public String toString() {
-            return "CallbackRecord[callback=" + mCallback + ", pkg=" + mPackageName
-                    + ", uid=" + mUid + ", pid=" + mPid + "]";
-        }
-
-        @Override
-        public void binderDied() {
-            synchronized (mLock) {
-                mCallbackRecords.remove(this);
-            }
-        }
-    }
-
-    final class FullUserRecord {
-        private final int mFullUserId;
-        private final SessionPriorityList mSessionPriorityList = new SessionPriorityList();
-
-        FullUserRecord(int fullUserId) {
-            mFullUserId = fullUserId;
-        }
-
-        public void addSession(Session2Record record) {
-            mSessionPriorityList.addSession(record);
-            mHandler.post(() -> dispatchSession2Created(record.mSessionToken));
-            mHandler.post(() -> dispatchSession2Changed(mFullUserId));
-        }
-
-        private void removeSession(Session2Record record) {
-            mSessionPriorityList.removeSession(record);
-            mHandler.post(() -> dispatchSession2Changed(mFullUserId));
-            //TODO: Handle if the removed session was the media button session.
-        }
-
-        public int getFullUserId() {
-            return mFullUserId;
-        }
-
-        public List<Session2Token> getAllSession2Tokens() {
-            return mSessionPriorityList.getAllTokens();
-        }
-
-        public List<Session2Token> getSession2Tokens(int userId) {
-            return mSessionPriorityList.getTokensByUserId(userId);
-        }
-
-        public void destroyAllSessions() {
-            mSessionPriorityList.destroyAllSessions();
-            mHandler.post(() -> dispatchSession2Changed(mFullUserId));
-        }
-
-        public void destroySessionsForUser(int userId) {
-            if (mSessionPriorityList.destroySessionsByUserId(userId)) {
-                mHandler.post(() -> dispatchSession2Changed(mFullUserId));
-            }
-        }
-
-        public boolean containsSession(Session2Record session) {
-            return mSessionPriorityList.contains(session);
-        }
-
-        public void onPlaybackStateChanged(Session2Record session, boolean promotePriority) {
-            mSessionPriorityList.onPlaybackStateChanged(session, promotePriority);
-        }
-    }
-
-    static final class Session2Record {
-        final Session2Token mSessionToken;
-        final Object mSession2RecordLock = new Object();
-        final WeakReference<MediaCommunicationService> mServiceRef;
-        final WeakReference<FullUserRecord> mFullUserRef;
-        @GuardedBy("mSession2RecordLock")
-        private final MediaController2 mController;
-
-        @GuardedBy("mSession2RecordLock")
-        boolean mIsConnected;
-        @GuardedBy("mSession2RecordLock")
-        private boolean mIsClosed;
-
-        //TODO: introduce policy (See MediaSessionPolicyProvider)
-        Session2Record(MediaCommunicationService service, FullUserRecord fullUser,
-                Session2Token token, Executor controllerExecutor) {
-            mServiceRef = new WeakReference<>(service);
-            mFullUserRef = new WeakReference<>(fullUser);
-            mSessionToken = token;
-            mController = new MediaController2.Builder(service.getContext(), token)
-                    .setControllerCallback(controllerExecutor, new Controller2Callback())
-                    .build();
-        }
-
-        public int getUserId() {
-            return UserHandle.getUserHandleForUid(mSessionToken.getUid()).getIdentifier();
-        }
-
-        public FullUserRecord getFullUser() {
-            return mFullUserRef.get();
-        }
-
-        public boolean isClosed() {
-            synchronized (mSession2RecordLock) {
-                return mIsClosed;
-            }
-        }
-
-        public void close() {
-            synchronized (mSession2RecordLock) {
-                mIsClosed = true;
-                mController.close();
-            }
-        }
-
-        public Session2Token getSessionToken() {
-            return mSessionToken;
-        }
-
-        public boolean checkPlaybackActiveState(boolean expected) {
-            synchronized (mSession2RecordLock) {
-                return mIsConnected && mController.isPlaybackActive() == expected;
-            }
-        }
-
-        private class Controller2Callback extends MediaController2.ControllerCallback {
-            @Override
-            public void onConnected(MediaController2 controller,
-                    Session2CommandGroup allowedCommands) {
-                if (DEBUG) {
-                    Log.d(TAG, "connected to " + mSessionToken + ", allowed=" + allowedCommands);
-                }
-                synchronized (mSession2RecordLock) {
-                    mIsConnected = true;
-                }
-            }
-
-            @Override
-            public void onDisconnected(MediaController2 controller) {
-                if (DEBUG) {
-                    Log.d(TAG, "disconnected from " + mSessionToken);
-                }
-                synchronized (mSession2RecordLock) {
-                    mIsConnected = false;
-                }
-                MediaCommunicationService service = mServiceRef.get();
-                if (service != null) {
-                    service.onSessionDied(Session2Record.this);
-                }
-            }
-
-            @Override
-            public void onPlaybackActiveChanged(
-                    @NonNull MediaController2 controller,
-                    boolean playbackActive) {
-                if (DEBUG) {
-                    Log.d(TAG, "playback active changed, " + mSessionToken + ", active="
-                            + playbackActive);
-                }
-                MediaCommunicationService service = mServiceRef.get();
-                if (service != null) {
-                    service.onSessionPlaybackStateChanged(Session2Record.this, playbackActive);
-                }
-            }
-        }
-    }
-}
diff --git a/apex/media/service/java/com/android/server/media/SessionPriorityList.java b/apex/media/service/java/com/android/server/media/SessionPriorityList.java
deleted file mode 100644
index 8145861..0000000
--- a/apex/media/service/java/com/android/server/media/SessionPriorityList.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright 2021 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.server.media;
-
-import android.annotation.Nullable;
-import android.media.Session2Token;
-import android.os.Build;
-import android.util.Log;
-
-import androidx.annotation.RequiresApi;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.modules.annotation.MinSdk;
-import com.android.server.media.MediaCommunicationService.Session2Record;
-
-import java.util.ArrayList;
-import java.util.List;
-
-//TODO: Define the priority specifically.
-/**
- * Keeps track of media sessions and their priority for notifications, media
- * button dispatch, etc.
- * Higher priority session has more chance to be selected as media button session,
- * which receives the media button events.
- */
-@MinSdk(Build.VERSION_CODES.S)
-@RequiresApi(Build.VERSION_CODES.S)
-class SessionPriorityList {
-    private static final String TAG = "SessionPriorityList";
-    private final Object mLock = new Object();
-
-    @GuardedBy("mLock")
-    private final List<Session2Record> mSessions = new ArrayList<>();
-
-    @Nullable
-    private Session2Record mMediaButtonSession;
-    @Nullable
-    private Session2Record mCachedVolumeSession;
-
-    //TODO: integrate AudioPlayerStateMonitor
-
-    public void addSession(Session2Record record) {
-        synchronized (mLock) {
-            mSessions.add(record);
-        }
-    }
-
-    public void removeSession(Session2Record record) {
-        synchronized (mLock) {
-            mSessions.remove(record);
-        }
-        if (record == mMediaButtonSession) {
-            updateMediaButtonSession(null);
-        }
-    }
-
-    public void destroyAllSessions() {
-        synchronized (mLock) {
-            for (Session2Record session : mSessions) {
-                session.close();
-            }
-            mSessions.clear();
-        }
-    }
-
-    public boolean destroySessionsByUserId(int userId) {
-        boolean changed = false;
-        synchronized (mLock) {
-            for (int i = mSessions.size() - 1; i >= 0; i--) {
-                Session2Record session = mSessions.get(i);
-                if (session.getUserId() == userId) {
-                    mSessions.remove(i);
-                    session.close();
-                    changed = true;
-                }
-            }
-        }
-        return changed;
-    }
-
-    public List<Session2Token> getAllTokens() {
-        List<Session2Token> sessions = new ArrayList<>();
-        synchronized (mLock) {
-            for (Session2Record session : mSessions) {
-                sessions.add(session.getSessionToken());
-            }
-        }
-        return sessions;
-    }
-
-    public List<Session2Token> getTokensByUserId(int userId) {
-        List<Session2Token> sessions = new ArrayList<>();
-        synchronized (mLock) {
-            for (Session2Record session : mSessions) {
-                if (session.getUserId() == userId) {
-                    sessions.add(session.getSessionToken());
-                }
-            }
-        }
-        return sessions;
-    }
-
-    /** Gets the media button session which receives the media button events. */
-    @Nullable
-    public Session2Record getMediaButtonSession() {
-        return mMediaButtonSession;
-    }
-
-    /** Gets the media volume session which receives the volume key events. */
-    @Nullable
-    public Session2Record getMediaVolumeSession() {
-        //TODO: if null, calculate it.
-        return mCachedVolumeSession;
-    }
-
-    public boolean contains(Session2Record session) {
-        synchronized (mLock) {
-            return mSessions.contains(session);
-        }
-    }
-
-    public void onPlaybackStateChanged(Session2Record session, boolean promotePriority) {
-        if (promotePriority) {
-            synchronized (mLock) {
-                if (mSessions.remove(session)) {
-                    mSessions.add(0, session);
-                } else {
-                    Log.w(TAG, "onPlaybackStateChanged: Ignoring unknown session");
-                    return;
-                }
-            }
-        } else if (session.checkPlaybackActiveState(false)) {
-            // Just clear the cached volume session when a state goes inactive
-            mCachedVolumeSession = null;
-        }
-
-        // In most cases, playback state isn't needed for finding the media button session,
-        // but we only use it as a hint if an app has multiple local media sessions.
-        // In that case, we pick the media session whose PlaybackState matches
-        // the audio playback configuration.
-        if (mMediaButtonSession != null
-                && mMediaButtonSession.getSessionToken().getUid()
-                == session.getSessionToken().getUid()) {
-            Session2Record newMediaButtonSession =
-                    findMediaButtonSession(mMediaButtonSession.getSessionToken().getUid());
-            if (newMediaButtonSession != mMediaButtonSession) {
-                // Check if the policy states that this session should not be updated as a media
-                // button session.
-                updateMediaButtonSession(newMediaButtonSession);
-            }
-        }
-    }
-
-    private void updateMediaButtonSession(@Nullable Session2Record newSession) {
-        mMediaButtonSession = newSession;
-        //TODO: invoke callbacks for media button session changed listeners
-    }
-
-    /**
-     * Finds the media button session with the given {@param uid}.
-     * If the app has multiple media sessions, the media session whose playback state is not null
-     * and matches the audio playback state becomes the media button session. Otherwise the top
-     * priority session becomes the media button session.
-     *
-     * @return The media button session. Returns {@code null} if the app doesn't have a media
-     *   session.
-     */
-    @Nullable
-    private Session2Record findMediaButtonSession(int uid) {
-        Session2Record mediaButtonSession = null;
-        synchronized (mLock) {
-            for (Session2Record session : mSessions) {
-                if (uid != session.getSessionToken().getUid()) {
-                    continue;
-                }
-                // TODO: check audio player state monitor
-                if (mediaButtonSession == null) {
-                    // Pick the top priority session as a default.
-                    mediaButtonSession = session;
-                }
-            }
-        }
-        return mediaButtonSession;
-    }
-}
diff --git a/apex/media/service/lint-baseline.xml b/apex/media/service/lint-baseline.xml
deleted file mode 100644
index def6baf..0000000
--- a/apex/media/service/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.2.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.2.0-dev">
-
-</issues>
diff --git a/media/java/Android.bp b/media/java/Android.bp
index c7c1d54..6878f9d 100644
--- a/media/java/Android.bp
+++ b/media/java/Android.bp
@@ -16,7 +16,9 @@
     exclude_srcs: [
         ":framework-media-tv-tunerresourcemanager-sources-aidl",
     ],
-    visibility: ["//frameworks/base"],
+    visibility: [
+        "//frameworks/base",
+    ],
 }
 
 filegroup {