Hướng dẫn di chuyển AndroidX Media3

Các ứng dụng hiện đang dùng thư viện com.google.android.exoplayer2 độc lập và androidx.media nên di chuyển sang androidx.media3. Sử dụng tập lệnh di chuyển để di chuyển các tệp bản dựng gradle, tệp nguồn Java và Kotlin cũng như tệp bố cục XML từ ExoPlayer 2.19.1 sang AndroidX Media3 1.1.1.

Tổng quan

Trước khi di chuyển, hãy xem các phần sau để tìm hiểu thêm về lợi ích của API mới, API cần di chuyển, cũng như các điều kiện tiên quyết mà dự án ứng dụng của bạn phải đáp ứng.

Lý do nên di chuyển sang Jetpack Media3

  • Đây là ngôi nhà mới của ExoPlayer, trong khi com.google.android.exoplayer2 không còn được dùng nữa.
  • Truy cập vào Player API trên các thành phần/quy trình bằng MediaBrowser/MediaController.
  • Hãy sử dụng các tính năng mở rộng của API MediaSessionMediaController.
  • Quảng cáo chức năng phát bằng chế độ kiểm soát quyền truy cập chi tiết.
  • Đơn giản hoá ứng dụng bằng cách xoá MediaSessionConnectorPlayerNotificationManager.
  • Tương thích ngược với các API ứng dụng tương thích với nội dung đa phương tiện (MediaBrowserCompat/MediaControllerCompat/MediaMetadataCompat)

Media API để di chuyển sang AndroidX Media3

  • ExoPlayer và các tiện ích của nó
    Trong đó bao gồm tất cả mô-đun của dự án ExoPlayer cũ, ngoại trừ mô-đun mediasession đã ngừng cung cấp. Bạn có thể di chuyển các ứng dụng hoặc mô-đun phụ thuộc vào các gói trong com.google.android.exoplayer2 bằng tập lệnh di chuyển.
  • MediaSessionConnector (tuỳ thuộc vào các gói androidx.media.* của androidx.media:media:1.4.3+)
    Hãy xoá MediaSessionConnector và sử dụng androidx.media3.session.MediaSession.
  • MediaBrowserServiceCompat (tuỳ thuộc vào các gói androidx.media.* của androidx.media:media:1.4.3+)
    Di chuyển các lớp con của androidx.media.MediaBrowserServiceCompat sang androidx.media3.session.MediaLibraryService và mã bằng MediaBrowserCompat.MediaItem sang androidx.media3.common.MediaItem.
  • MediaBrowserCompat (tuỳ thuộc vào các gói android.support.v4.media.* của androidx.media:media:1.4.3+)
    Di chuyển mã ứng dụng khách bằng MediaBrowserCompat hoặc MediaControllerCompat để sử dụng androidx.media3.session.MediaBrowser với androidx.media3.common.MediaItem.

Điều kiện tiên quyết

  1. Đảm bảo dự án của bạn đang ở chế độ kiểm soát nguồn

    Đảm bảo bạn có thể dễ dàng huỷ bỏ những thay đổi do các công cụ di chuyển theo tập lệnh áp dụng. Nếu bạn chưa có dự án ở chế độ kiểm soát nguồn, thì bây giờ là thời điểm thích hợp để bắt đầu. Nếu vì lý do nào đó bạn không muốn làm điều đó, hãy tạo một bản sao dự phòng của dự án trước khi bắt đầu quá trình di chuyển.

  2. Cập nhật ứng dụng

    • Bạn nên cập nhật dự án để sử dụng phiên bản mới nhất của thư viện ExoPlayer và xoá mọi lệnh gọi đến các phương thức không dùng nữa. Nếu có ý định sử dụng tập lệnh cho quá trình di chuyển, bạn cần phải so khớp phiên bản đang cập nhật với phiên bản do tập lệnh xử lý.

    • Tăng compileSdkVersion của ứng dụng lên tối thiểu là 32.

    • Nâng cấp Gradle và trình bổ trợ Gradle cho Android Studio lên một phiên bản gần đây hoạt động được với các phần phụ thuộc đã cập nhật ở trên. Ví dụ:

      • Phiên bản trình bổ trợ Android cho Gradle: 7.1.0
      • Phiên bản Gradle: 7.4
    • Thay thế tất cả câu lệnh nhập ký tự đại diện đang dùng dấu asterix (*) và sử dụng các câu lệnh nhập đủ điều kiện: Xoá các câu lệnh nhập ký tự đại diện và sử dụng Android Studio để nhập những câu lệnh đủ điều kiện (F2 – Alt/Enter, F2 – Alt/Enter, ...).

    • Di chuyển từ com.google.android.exoplayer2.PlayerView sang com.google.android.exoplayer2.StyledPlayerView. Điều này là cần thiết vì không có dữ liệu tương đương với com.google.android.exoplayer2.PlayerView trong AndroidX Media3.

Di chuyển ExoPlayer có hỗ trợ tập lệnh

Tập lệnh hỗ trợ việc di chuyển từ com.google.android.exoplayer2 sang cấu trúc gói và mô-đun mới trong androidx.media3. Tập lệnh sẽ áp dụng một số quy trình kiểm tra xác thực cho dự án của bạn và in cảnh báo nếu quá trình xác thực không thành công. Nếu không, lệnh này sẽ áp dụng bản đồ ánh xạ của các lớp và gói đã đổi tên trong tài nguyên của một dự án Android gradle được viết bằng Java hoặc Kotlin.

usage: ./media3-migration.sh [-p|-c|-d|-v]|[-m|-l [-x <path>] [-f] PROJECT_ROOT]
 PROJECT_ROOT: path to your project root (location of 'gradlew')
 -p: list package mappings and then exit
 -c: list class mappings (precedence over package mappings) and then exit
 -d: list dependency mappings and then exit
 -l: list files that will be considered for rewrite and then exit
 -x: exclude the path from the list of file to be changed: 'app/src/test'
 -m: migrate packages, classes and dependencies to AndroidX Media3
 -f: force the action even when validation fails
 -v: print the exoplayer2/media3 version strings of this script
 -h, --help: show this help text

Sử dụng tập lệnh di chuyển

  1. Tải tập lệnh di chuyển xuống từ thẻ của dự án ExoPlayer trên GitHub tương ứng với phiên bản mà bạn đã cập nhật ứng dụng:

    curl -o media3-migration.sh \
      "https://raw.githubusercontent.com/google/ExoPlayer/r2.19.1/media3-migration.sh"
    
  2. Làm cho tập lệnh có thể thực thi:

    chmod 744 media3-migration.sh
    
  3. Chạy tập lệnh bằng --help để tìm hiểu về các tuỳ chọn.

  4. Chạy tập lệnh bằng -l để liệt kê tập hợp các tệp được chọn để di chuyển (sử dụng -f để buộc trang thông tin không có cảnh báo):

    ./media3-migration.sh -l -f /path/to/gradle/project/root
    
  5. Chạy tập lệnh bằng -m để ánh xạ các gói, lớp và mô-đun với Media3. Việc chạy tập lệnh với tuỳ chọn -m sẽ áp dụng các thay đổi cho các tệp đã chọn.

    • Dừng lại ở lỗi xác thực mà không thay đổi
    ./media3-migration.sh -m /path/to/gradle/project/root
    
    • Thực thi bắt buộc

    Nếu tập lệnh tìm thấy lỗi vi phạm các điều kiện tiên quyết, thì bạn có thể buộc di chuyển bằng cờ -f:

    ./media3-migration.sh -m -f /path/to/gradle/project/root
    
 # list files selected for migration when excluding paths
 ./media3-migration.sh -l -x "app/src/test/" -x "service/" /path/to/project/root
 # migrate the selected files
 ./media3-migration.sh -m -x "app/src/test/" -x "service/" /path/to/project/root

Hoàn thành các bước thủ công này sau khi chạy tập lệnh bằng tuỳ chọn -m:

  1. Kiểm tra cách tập lệnh đã thay đổi mã của bạn: Sử dụng công cụ so sánh và khắc phục các vấn đề tiềm ẩn (hãy cân nhắc gửi lỗi nếu bạn cho rằng tập lệnh gặp sự cố chung đã xảy ra mà không chuyển tuỳ chọn -f).
  2. Tạo dự án: Sử dụng ./gradlew clean build hoặc trong Android Studio, chọn Tệp > Đồng bộ hoá dự án với tệp Gradle, sau đó chọn Xây dựng > Làm sạch dự án, rồi chọn Xây dựng > Xây dựng lại dự án (theo dõi bản dựng của bạn trong thẻ "Tạo – Đầu ra của bản dựng" của Android Studio.

Các bước tiếp theo được đề xuất:

  1. Giải quyết chọn nhận lỗi liên quan đến việc sử dụng API không ổn định.
  2. Thay thế các lệnh gọi API không dùng nữa: Dùng API thay thế được đề xuất. Giữ con trỏ trên cảnh báo trong Android Studio rồi tham khảo JavaDoc của biểu tượng không dùng nữa để tìm hiểu cần sử dụng gì thay cho một lệnh gọi cụ thể.
  3. Sắp xếp các câu lệnh nhập: Mở dự án trong Android Studio, sau đó nhấp chuột phải vào nút thư mục gói trong trình xem dự án và chọn Tối ưu hoá lệnh nhập trên các gói chứa tệp nguồn đã thay đổi.

Thay thế MediaSessionConnector bằng androidx.media3.session.MediaSession.

Trong thế giới MediaSessionCompat cũ, MediaSessionConnector chịu trách nhiệm đồng bộ hoá trạng thái của người chơi với trạng thái của phiên hoạt động và nhận các lệnh từ các bộ điều khiển cần uỷ quyền sang các phương thức phù hợp cho người chơi. Với AndroidX Media3, việc này được MediaSession thực hiện trực tiếp mà không cần có trình kết nối.

  1. Xoá tất cả các tham chiếu và mục sử dụng MediaSessionConnector: Nếu bạn đã sử dụng tập lệnh tự động để di chuyển các lớp và gói ExoPlayer, thì tập lệnh có thể đã để mã của bạn ở trạng thái không thể biên dịch được liên quan đến MediaSessionConnector mà không thể giải quyết được. Android Studio sẽ cho bạn thấy đoạn mã bị hỏng khi bạn cố gắng tạo hoặc khởi động ứng dụng.

  2. Trong tệp build.gradle nơi bạn duy trì các phần phụ thuộc, hãy thêm phần phụ thuộc triển khai vào mô-đun phiên AndroidX Media3 và xoá phần phụ thuộc cũ:

    implementation "androidx.media3:media3-session:1.3.1"
    
  3. Thay thế MediaSessionCompat bằng androidx.media3.session.MediaSession.

  4. Tại trang web mã mà bạn đã tạo MediaSessionCompat cũ, hãy dùng androidx.media3.session.MediaSession.Builder để tạo MediaSession. Truyền trình phát để tạo trình tạo phiên.

    val player = ExoPlayer.Builder(context).build()
    mediaSession = MediaSession.Builder(context, player)
        .setSessionCallback(MySessionCallback())
        .build()
    
  5. Triển khai MySessionCallback theo yêu cầu của ứng dụng. Triển khai (không bắt buộc). Nếu bạn muốn cho phép tay điều khiển thêm các mục nội dung nghe nhìn vào trình phát, hãy triển khai MediaSession.Callback.onAddMediaItems(). Thư viện này phân phát nhiều phương thức API hiện tại và cũ, giúp thêm các mục nội dung nghe nhìn vào trình phát để phát theo cách tương thích ngược. Trong đó bao gồm các phương thức MediaController.set/addMediaItems() của trình điều khiển Media3, cũng như các phương thức TransportControls.prepareFrom*/playFrom* của API cũ. Bạn có thể xem cách triển khai mẫu của onAddMediaItems trong PlaybackService của ứng dụng minh hoạ phiên.

  6. Phát hành phiên nội dung nghe nhìn tại trang web mã mà bạn đã huỷ phiên đó trước khi di chuyển:

    mediaSession?.run {
      player.release()
      release()
      mediaSession = null
    }
    

Chức năng MediaSessionConnector trong Media3

Bảng sau đây cho thấy các API Media3 xử lý chức năng đã triển khai trước đó trong MediaSessionConnector.

MediaSessionMediaAndroidX Media3
CustomActionProvider MediaSession.Callback.onCustomCommand()/ MediaSession.setCustomLayout()
PlaybackPreparer MediaSession.Callback.onAddMediaItems() (prepare() được gọi nội bộ)
QueueNavigator ForwardingPlayer
QueueEditor MediaSession.Callback.onAddMediaItems()
RatingCallback MediaSession.Callback.onSetRating()
PlayerNotificationManager DefaultMediaNotificationProvider/ MediaNotification.Provider

Di chuyển MediaBrowserService sang MediaLibraryService

AndroidX Media3 ra mắt MediaLibraryService thay thế cho MediaBrowserServiceCompat. JavaDoc của MediaLibraryService và lớp cấp cao MediaSessionService cung cấp phần giới thiệu tốt về API và mô hình lập trình không đồng bộ của dịch vụ.

MediaLibraryService tương thích ngược với MediaBrowserService. Một ứng dụng khách đang dùng MediaBrowserCompat hoặc MediaControllerCompat, tiếp tục hoạt động mà không cần thay đổi mã khi kết nối với MediaLibraryService. Đối với ứng dụng, bạn phải minh bạch việc ứng dụng của mình đang sử dụng MediaLibraryService hay MediaBrowserServiceCompat cũ.

Sơ đồ thành phần ứng dụng có dịch vụ, hoạt động và ứng dụng bên ngoài.
Hình 1: Tổng quan về thành phần ứng dụng đa phương tiện
  1. Để khả năng tương thích ngược hoạt động, bạn cần đăng ký cả hai giao diện dịch vụ với dịch vụ của mình trong AndroidManifest.xml. Theo cách này, ứng dụng tìm thấy dịch vụ của bạn qua giao diện dịch vụ bắt buộc:

    <service android:name=".MusicService" android:exported="true">
        <intent-filter>
            <action android:name="androidx.media3.session.MediaLibraryService"/>
            <action android:name="android.media.browse.MediaBrowserService" />
        </intent-filter>
    </service>
    
  2. Trong tệp build.gradle nơi bạn duy trì các phần phụ thuộc, hãy thêm phần phụ thuộc triển khai vào mô-đun phiên AndroidX Media3 và xoá phần phụ thuộc cũ:

    implementation "androidx.media3:media3-session:1.3.1"
    
  3. Thay đổi dịch vụ để kế thừa từ MediaLibraryService thay vì MediaBrowserService Như đã nói trước đó, MediaLibraryService tương thích với MediaBrowserService cũ. Theo đó, API rộng hơn mà dịch vụ đang cung cấp cho ứng dụng vẫn không thay đổi. Vì vậy, có khả năng ứng dụng có thể giữ lại hầu hết logic cần thiết để triển khai MediaBrowserService và điều chỉnh cho phù hợp với MediaLibraryService mới.

    Sau đây là những điểm khác biệt chính so với MediaBrowserServiceCompat cũ:

    • Triển khai các phương thức trong vòng đời của dịch vụ: Các phương thức cần được ghi đè trên chính dịch vụ là onCreate/onDestroy, trong đó một ứng dụng phân bổ/phát hành phiên thư viện, trình phát và các tài nguyên khác. Ngoài các phương thức vòng đời dịch vụ tiêu chuẩn, một ứng dụng cần ghi đè onGetSession(MediaSession.ControllerInfo) để trả về MediaLibrarySession đã được tích hợp trong onCreate.

    • Triển khai MediaLibraryService.MediaLibrarySessionCallback: Việc tạo một phiên hoạt động yêu cầu một MediaLibraryService.MediaLibrarySessionCallback triển khai các phương thức API của miền thực tế. Vì vậy, thay vì ghi đè các phương thức API của dịch vụ cũ, bạn sẽ ghi đè các phương thức của MediaLibrarySession.Callback.

      Sau đó, lệnh gọi lại được dùng để tạo MediaLibrarySession:

      mediaLibrarySession =
            MediaLibrarySession.Builder(this, player, MySessionCallback())
               .build()
      

      Tìm API đầy đủ của MediaLibrarySessionCallback trong tài liệu về API.

    • Triển khai MediaSession.Callback.onAddMediaItems(): Lệnh gọi lại onAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>) phân phát nhiều phương thức API hiện tại và cũ để thêm các mục nội dung nghe nhìn vào trình phát để phát theo cách tương thích ngược. Trong đó bao gồm các phương thức MediaController.set/addMediaItems() của trình điều khiển Media3, cũng như các phương thức TransportControls.prepareFrom*/playFrom* của API cũ. Bạn có thể xem cách triển khai mẫu của lệnh gọi lại trong PlaybackService của ứng dụng minh hoạ phiên.

    • AndroidX Media3 đang sử dụng androidx.media3.common.MediaItem thay vì MediaBrowserCompat.MediaItemMediaMetadataCompat. Bạn cần thay đổi các phần của mã liên kết với các lớp cũ cho phù hợp hoặc ánh xạ tới MediaItem Media3.

    • Mô hình lập trình không đồng bộ chung thay đổi thành Futures trái ngược với phương thức Result có thể tháo rời của MediaBrowserServiceCompat. Quá trình triển khai dịch vụ có thể trả về một ListenableFuture không đồng bộ thay vì tách một kết quả hoặc trả về một Future ngay lập tức để trực tiếp trả về một giá trị.

Xóa PlayerNotificationManager

MediaLibraryService tự động hỗ trợ các thông báo về nội dung nghe nhìn và bạn có thể xoá PlayerNotificationManager khi sử dụng MediaLibraryService hoặc MediaSessionService.

Ứng dụng có thể tuỳ chỉnh thông báo bằng cách đặt MediaNotification.Provider tuỳ chỉnh trong onCreate() thay thế DefaultMediaNotificationProvider. Sau đó, MediaLibraryService sẽ đảm nhận việc khởi động dịch vụ ở nền trước theo yêu cầu.

Bằng cách ghi đè MediaLibraryService.updateNotification(), ứng dụng có thể nắm toàn quyền sở hữu đối với việc đăng thông báo và bắt đầu/dừng dịch vụ ở nền trước nếu cần.

Di chuyển mã ứng dụng bằng MediaBrowser

Với AndroidX Media3, MediaBrowser sẽ triển khai các giao diện MediaController/Player và có thể dùng để điều khiển việc phát nội dung nghe nhìn bên cạnh việc duyệt thư viện nội dung nghe nhìn. Nếu phải tạo MediaBrowserCompatMediaControllerCompat trong thế giới cũ, bạn có thể thực hiện tương tự bằng cách chỉ sử dụng MediaBrowser trong Media3.

Bạn có thể tạo MediaBrowser và chờ kết nối với dịch vụ đang được thiết lập:

scope.launch {
    val sessionToken =
        SessionToken(context, ComponentName(context, MusicService::class.java)
    browser =
        MediaBrowser.Builder(context, sessionToken))
            .setListener(BrowserListener())
            .buildAsync()
            .await()
    // Get the library root to start browsing the library.
    root = browser.getLibraryRoot(/* params= */ null).await();
    // Add a MediaController.Listener to listen to player state events.
    browser.addListener(playerListener)
    playerView.setPlayer(browser)
}

Hãy xem bài viết Điều khiển chế độ phát trong phiên phát nội dung đa phương tiện để tìm hiểu cách tạo MediaController nhằm điều khiển chế độ phát ở chế độ nền.

Các bước tiếp theo và dọn dẹp

Lỗi API không ổn định

Sau khi di chuyển sang Media3, bạn có thể thấy lỗi tìm lỗi mã nguồn cho biết cách sử dụng API không ổn định. Các API này an toàn để sử dụng và lỗi tìm lỗi mã nguồn là sản phẩm phụ của các đảm bảo về khả năng tương thích nhị phân mới của chúng tôi. Nếu không yêu cầu khả năng tương thích nhị phân nghiêm ngặt, bạn có thể chặn các lỗi này một cách an toàn bằng chú giải @OptIn.

Thông tin khái quát

Cả ExoPlayer v1 hoặc v2 đều không đảm bảo nghiêm ngặt về khả năng tương thích nhị phân của thư viện giữa các phiên bản tiếp theo. Bề mặt API ExoPlayer có thiết kế rất lớn, cho phép các ứng dụng tuỳ chỉnh hầu hết mọi khía cạnh của quá trình phát. Các phiên bản tiếp theo của ExoPlayer đôi khi sẽ đổi tên biểu tượng hoặc thay đổi có thể gây lỗi khác (ví dụ: các phương thức bắt buộc mới trên giao diện). Trong hầu hết các trường hợp, sự cố này đã được giảm thiểu bằng cách cho ra mắt biểu tượng mới, đồng thời ngừng sử dụng biểu tượng cũ trong một số phiên bản, để nhà phát triển có thời gian di chuyển dữ liệu sử dụng của mình. Tuy nhiên, không phải lúc nào cũng làm được.

Những thay đổi có thể gây lỗi này đã gây ra 2 vấn đề cho người dùng thư viện ExoPlayer v1 và v2:

  1. Việc nâng cấp lên phiên bản ExoPlayer có thể khiến mã ngừng biên dịch.
  2. Một ứng dụng phụ thuộc trực tiếp vào ExoPlayer cả trực tiếp và thông qua thư viện trung gian phải đảm bảo rằng cả hai phần phụ thuộc đều là cùng một phiên bản. Nếu không, sự không tương thích của tệp nhị phân có thể dẫn đến sự cố trong thời gian chạy.

Các điểm cải tiến trong Media3

Media3 đảm bảo khả năng tương thích nhị phân cho một tập hợp con nền tảng API. Những phần không đảm bảo khả năng tương thích tệp nhị phân sẽ được đánh dấu bằng @UnstableApi. Để làm rõ sự khác biệt này, việc sử dụng các biểu tượng API không ổn định sẽ tạo ra lỗi tìm lỗi mã nguồn, trừ phi các biểu tượng đó được chú thích bằng @OptIn.

Sau khi di chuyển từ ExoPlayer v2 sang Media3, bạn có thể thấy nhiều lỗi tìm lỗi mã nguồn API không ổn định. Điều này có thể khiến Media3 có vẻ "kém ổn định hơn" so với ExoPlayer phiên bản 2. Không phải lúc này. Các phần "không ổn định" của API Media3 có cùng mức độ ổn định toàn bộ nền tảng API ExoPlayer v2, và việc đảm bảo giao diện API Media3 ổn định sẽ không có trong ExoPlayer v2. Điểm khác biệt đơn giản là giờ đây một lỗi tìm lỗi mã nguồn sẽ cảnh báo cho bạn về các mức độ ổn định khác nhau.

Xử lý lỗi tìm lỗi mã nguồn API không ổn định

Bạn có hai lựa chọn để xử lý các lỗi tìm lỗi mã nguồn API không ổn định:

  • Chuyển sang sử dụng một API ổn định đạt được kết quả tương tự.
  • Tiếp tục sử dụng API không ổn định và chú thích việc sử dụng bằng @OptIn.

    import androidx.annotation.OptIn
    import androidx.media3.common.util.UnstableApi
    
    @OptIn(UnstableApi::class)
    fun functionUsingUnstableApi() {
      // Do something useful.
    }
    

    Xin lưu ý rằng cũng có một chú giải kotlin.OptIn mà bạn không nên sử dụng. Điều quan trọng là bạn phải sử dụng chú giải androidx.annotation.OptIn cho mục đích này.

    Ảnh chụp màn hình: Cách thêm chú thích Optin
    Hình 2: Thêm chú thích @androidx.annotation.OptIn bằng Android Studio.

Bạn có thể chọn tham gia cho toàn bộ gói bằng cách thêm một package-info.java:

@OptIn(markerClass = UnstableApi.class)
package name.of.your.package;

import androidx.annotation.OptIn;
import androidx.media3.common.util.UnstableApi;

Bạn có thể chọn áp dụng cho toàn bộ dự án bằng cách loại bỏ lỗi tìm lỗi mã nguồn cụ thể trong tệp lint.xml. Hãy xem JavaDoc của chú thích UnstableApi để biết thêm thông tin chi tiết.

API không dùng nữa

Bạn có thể nhận thấy rằng các lệnh gọi đến các API không dùng nữa sẽ bị gạch ngang trong Android Studio. Bạn nên thay thế các lệnh gọi như vậy bằng phương thức thay thế thích hợp. Di chuột qua biểu tượng này để xem JavaDoc cho biết cần sử dụng API nào.

Ảnh chụp màn hình: Cách hiển thị JavaDoc bằng phương thức thay thế không được dùng nữa
Hình 3: Phần chú thích JavaDoc trong Android Studio đề xuất phương án thay thế cho mọi biểu tượng không dùng nữa.

Mã mẫu và ứng dụng minh hoạ

  • Ứng dụng minh hoạ phiên AndroidX Media3 (thiết bị di động và WearOS)
    • Thao tác tuỳ chỉnh
    • Thông báo giao diện người dùng hệ thống, MediaButton/BT
    • Bộ điều khiển chế độ phát của Trợ lý Google
  • UAMP: Android Media Player (nhánh media3) (thiết bị di động, AutomotiveOS)
    • Thông báo về Giao diện người dùng hệ thống, MediaButton/BT, Tiếp tục phát
    • Bộ điều khiển chế độ phát trên WearOS/Trợ lý Google
    • AutomotiveOS: lệnh và đăng nhập tuỳ chỉnh