Thêm video bằng tính năng hình trong hình (PiP)

Thử cách dùng Compose
Jetpack Compose là bộ công cụ giao diện người dùng được đề xuất cho Android. Tìm hiểu cách hỗ trợ chế độ hình trong hình trong Compose.

Kể từ Android 8.0 (API cấp 26), Android sẽ cho phép chạy các hoạt động ở chế độ Hình trong hình (PiP). PiP là một loại chế độ đặc biệt dành cho nhiều cửa sổ, chủ yếu dùng để phát video. Tính năng này cho phép người dùng xem video trong một cửa sổ nhỏ được ghim vào góc màn hình trong khi di chuyển giữa các ứng dụng hoặc duyệt xem nội dung trên màn hình chính.

PiP tận dụng các API nhiều cửa sổ có trong Android 7.0 để cung cấp cửa sổ lớp phủ của video đã ghim. Để thêm PiP vào ứng dụng, bạn cần đăng ký các hoạt động hỗ trợ PiP, chuyển hoạt động sang Chế độ PiP (nếu cần) và đảm bảo ẩn đi các thành phần giao diện người dùng cũng như tiếp tục phát video khi hoạt động đó được ở chế độ PiP.

Cửa sổ PiP xuất hiện ở lớp trên cùng của màn hình, ở một góc mà hệ thống chọn.

Chế độ PiP cũng được hỗ trợ trên các thiết bị Android TV OS tương thích chạy Android 14 (API cấp 34) trở lên. Mặc dù có nhiều điểm tương đồng, nhưng vẫn có một số điểm cần cân nhắc khác khi sử dụng PiP trên TV.

Cách người dùng có thể tương tác với cửa sổ PiP

Người dùng có thể kéo cửa sổ PiP đến một vị trí khác. Kể từ Android 12, người dùng cũng có thể:

  • Nhấn một lần vào cửa sổ để hiện nút bật/tắt chế độ toàn màn hình, nút đóng, nút cài đặt và các hành động tuỳ chỉnh mà ứng dụng của bạn cung cấp (ví dụ: nút điều khiển trình phát).

  • Nhấn đúp vào cửa sổ để chuyển đổi giữa kích thước PiP hiện tại và kích thước PiP tối đa hoặc tối thiểu. Ví dụ: nhấn đúp vào cửa sổ được phóng to sẽ thu nhỏ cửa sổ đó và ngược lại.

  • Lưu trữ cửa sổ bằng cách kéo cửa sổ sang cạnh trái hoặc phải. Để huỷ lưu trữ cửa sổ, hãy nhấn vào phần hiển thị của cửa sổ đã lưu trữ hoặc kéo cửa sổ đó ra.

  • Đổi kích thước cửa sổ PiP bằng cách chụm để thu phóng.

Ứng dụng của bạn kiểm soát thời điểm hoạt động hiện tại chuyển sang chế độ PiP. Dưới đây là một số ví dụ:

  • Một hoạt động có thể chuyển sang chế độ PiP khi người dùng nhấn vào nút màn hình chính hoặc vuốt lên để về màn hình chính. Đây là cách Google Maps không ngừng hiển thị thông tin đường đi trong khi người dùng chạy một hoạt động khác cùng một lúc.

  • Ứng dụng của bạn có thể chuyển video sang chế độ PiP khi người dùng quay lại video để duyệt qua nội dung khác.

  • Ứng dụng của bạn có thể chuyển video sang chế độ PiP trong khi người dùng xem đến cuối tập nội dung. Màn hình chính cho thấy thông tin quảng bá hoặc tóm tắt về tập tiếp theo trong loạt video.

  • Ứng dụng của bạn có thể giúp người dùng thêm nội dung bổ sung vào hàng đợi trong khi xem video. Video sẽ tiếp tục phát ở chế độ PiP trong khi màn hình chính hiện một hoạt động lựa chọn nội dung.

Khai báo tính năng hỗ trợ PiP

Theo mặc định, hệ thống không tự động hỗ trợ tính năng PiP cho ứng dụng. Nếu bạn muốn hỗ trợ tính năng PiP trong ứng dụng của mình, hãy đăng ký hoạt động video trong tệp kê khai bằng cách đặt android:supportsPictureInPicture thành true. Ngoài ra, hãy chỉ định rằng hoạt động của bạn xử lý các thay đổi đối với cấu hình bố cục để hoạt động của bạn không chạy lại khi các thay đổi về bố cục xảy ra trong quá trình chuyển đổi chế độ PiP.

<activity android:name="VideoActivity"
    android:supportsPictureInPicture="true"
    android:configChanges=
        "screenSize|smallestScreenSize|screenLayout|orientation"
    ...

Chuyển hoạt động sang chế độ PiP

Kể từ Android 12, bạn có thể chuyển hoạt động sang chế độ PiP bằng cách đặt cờ setAutoEnterEnabled thành true. Với chế độ cài đặt này, một hoạt động sẽ tự động chuyển sang chế độ PiP khi cần mà không cần gọi enterPictureInPictureMode() một cách rõ ràng trong onUserLeaveHint. Điều này cũng mang lại lợi ích bổ sung là cung cấp các chuyển đổi mượt mà hơn nhiều. Để biết thông tin chi tiết, hãy xem phần Khiến việc chuyển đổi sang chế độ PiP mượt mà hơn khi thao tác bằng cử chỉ.

Nếu bạn đang nhắm đến Android 11 trở xuống, thì một hoạt động phải gọi enterPictureInPictureMode() để chuyển sang chế độ PiP. Ví dụ: mã sau đây sẽ chuyển một hoạt động sang chế độ PiP khi người dùng nhấp vào một nút riêng trong giao diện người dùng của ứng dụng:

Kotlin

override fun onActionClicked(action: Action) {
    if (action.id.toInt() == R.id.lb_control_picture_in_picture) {
        activity?.enterPictureInPictureMode()
        return
    }
}

Java

@Override
public void onActionClicked(Action action) {
    if (action.getId() == R.id.lb_control_picture_in_picture) {
        getActivity().enterPictureInPictureMode();
        return;
    }
    ...
}

Bạn nên thêm logic chuyển một hoạt động sang chế độ PiP thay vì chuyển vào chế độ nền. Ví dụ: Google Maps sẽ chuyển sang chế độ PiP nếu người dùng nhấn nút màn hình chính hoặc nút gần đây trong khi ứng dụng đang đi theo chỉ dẫn. Bạn có thể xác định trường hợp này bằng cách ghi đè onUserLeaveHint():

Kotlin

override fun onUserLeaveHint() {
    if (iWantToBeInPipModeNow()) {
        enterPictureInPictureMode()
    }
}

Java

@Override
public void onUserLeaveHint () {
    if (iWantToBeInPipModeNow()) {
        enterPictureInPictureMode();
    }
}

Nên: mang đến cho người dùng trải nghiệm chuyển đổi PiP chỉn chu

Android 12 đã bổ sung các điểm cải tiến đáng kể về giao diện cho hiệu ứng chuyển đổi ảnh động giữa cửa sổ toàn màn hình và cửa sổ PiP. Bạn nên triển khai tất cả các thay đổi có thể áp dụng. Sau khi bạn thực hiện, những thay đổi này sẽ tự động mở rộng quy mô sang màn hình lớn, chẳng hạn như thiết bị có thể gập lại và máy tính bảng mà không cần làm gì thêm.

Nếu ứng dụng của bạn không bao gồm các bản cập nhật hiện hành, thì hiệu ứng chuyển đổi PiP vẫn hoạt động nhưng ảnh động sẽ kém tinh tế hơn. Ví dụ: việc chuyển từ chế độ toàn màn hình sang chế độ PiP có thể khiến cửa sổ PiP biến mất trong quá trình chuyển đổi trước khi cửa sổ này xuất hiện trở lại khi quá trình chuyển đổi hoàn tất.

Những thay đổi này bao gồm những nội dung sau.

  • Khiến việc chuyển đổi sang chế độ PiP mượt mà hơn khi thao tác bằng cử chỉ
  • Đặt sourceRectHint thích hợp để chuyển vào và thoát khỏi chế độ PiP
  • Tắt tính năng đổi kích thước liền mạch cho nội dung không phải video

Tham khảo mẫu PictureInPicture Kotlin cho Android làm tài liệu tham khảo để mang lại trải nghiệm chuyển đổi tinh tế.

Khiến việc chuyển đổi sang chế độ PiP mượt mà hơn khi thao tác bằng cử chỉ

Kể từ Android 12, cờ setAutoEnterEnabled sẽ cung cấp ảnh động mượt mà hơn nhiều để chuyển đổi sang nội dung video ở chế độ PiP bằng thao tác bằng cử chỉ, ví dụ: khi vuốt lên màn hình chính từ chế độ toàn màn hình.

Hãy hoàn thành các bước sau để thực hiện thay đổi này và tham khảo mẫu này:

  1. Sử dụng setAutoEnterEnabled để tạo PictureInPictureParams.Builder:

    Kotlin

    setPictureInPictureParams(PictureInPictureParams.Builder()
        .setAspectRatio(aspectRatio)
        .setSourceRectHint(sourceRectHint)
        .setAutoEnterEnabled(true)
        .build())

    Java

    setPictureInPictureParams(new PictureInPictureParams.Builder()
        .setAspectRatio(aspectRatio)
        .setSourceRectHint(sourceRectHint)
        .setAutoEnterEnabled(true)
        .build());
  2. Gọi setPictureInPictureParams thông báo sớm PictureInPictureParams. Ứng dụng không đợi lệnh gọi lại onUserLeaveHint (như đã xảy ra trong Android 11).

    Ví dụ: bạn có thể muốn gọi setPictureInPictureParams trong lần phát đầu tiên và mọi lần phát sau nếu tỷ lệ khung hình thay đổi.

  3. Gọi setAutoEnterEnabled(false), nhưng chỉ khi cần thiết. Ví dụ: bạn có thể không muốn chuyển sang chế độ PiP nếu hoạt động phát hiện tại đang ở trạng thái tạm dừng.

Đặt sourceRectHint thích hợp để chuyển sang và thoát khỏi chế độ PiP

Bắt đầu từ khi tính năng PiP ra mắt trong Android 8.0, setSourceRectHint cho biết khu vực hoạt động hiển thị sau khi chuyển sang chế độ hình trong hình, ví dụ: giới hạn xem video trong trình phát video.

Với Android 12, hệ thống sử dụng sourceRectHint để triển khai ảnh động mượt mà hơn nhiều cả khi vào và thoát chế độ PiP.

Cách đặt sourceRectHint đúng cách để chuyển sang và thoát khỏi chế độ PiP:

  1. Tạo PictureInPictureParams bằng cách sử dụng các giới hạn thích hợp dưới dạng sourceRectHint. Bạn cũng nên đính kèm trình nghe thay đổi bố cục vào trình phát video:

    Kotlin

    val mOnLayoutChangeListener =
    OnLayoutChangeListener { v: View?, oldLeft: Int,
            oldTop: Int, oldRight: Int, oldBottom: Int, newLeft: Int, newTop:
            Int, newRight: Int, newBottom: Int ->
        val sourceRectHint = Rect()
        mYourVideoView.getGlobalVisibleRect(sourceRectHint)
        val builder = PictureInPictureParams.Builder()
            .setSourceRectHint(sourceRectHint)
        setPictureInPictureParams(builder.build())
    }
    
    mYourVideoView.addOnLayoutChangeListener(mOnLayoutChangeListener)

    Java

    private final View.OnLayoutChangeListener mOnLayoutChangeListener =
            (v, oldLeft, oldTop, oldRight, oldBottom, newLeft, newTop, newRight,
            newBottom) -> {
        final Rect sourceRectHint = new Rect();
        mYourVideoView.getGlobalVisibleRect(sourceRectHint);
        final PictureInPictureParams.Builder builder =
            new PictureInPictureParams.Builder()
                .setSourceRectHint(sourceRectHint);
        setPictureInPictureParams(builder.build());
    };
    
    mYourVideoView.addOnLayoutChangeListener(mOnLayoutChangeListener);
  2. Nếu cần, hãy cập nhật sourceRectHint trước khi hệ thống bắt đầu quá trình chuyển đổi thoát. Khi hệ thống sắp thoát khỏi chế độ PiP, hệ phân cấp khung hiển thị của hoạt động sẽ được đưa vào cấu hình đích (ví dụ: toàn màn hình). Ứng dụng có thể đính kèm trình nghe thay đổi bố cục vào chế độ xem gốc hoặc chế độ xem mục tiêu (chẳng hạn như chế độ xem trình phát video) để phát hiện sự kiện và cập nhật sourceRectHint trước khi ảnh động bắt đầu.

    Kotlin

    // Listener is called immediately after the user exits PiP but before animating.
    playerView.addOnLayoutChangeListener { _, left, top, right, bottom,
                        oldLeft, oldTop, oldRight, oldBottom ->
        if (left != oldLeft
            || right != oldRight
            || top != oldTop
            || bottom != oldBottom) {
            // The playerView's bounds changed, update the source hint rect to
            // reflect its new bounds.
            val sourceRectHint = Rect()
            playerView.getGlobalVisibleRect(sourceRectHint)
            setPictureInPictureParams(
                PictureInPictureParams.Builder()
                    .setSourceRectHint(sourceRectHint)
                    .build()
            )
        }
    }

    Java

    // Listener is called right after the user exits PiP but before animating.
    playerView.addOnLayoutChangeListener((v, left, top, right, bottom,
                        oldLeft, oldTop, oldRight, oldBottom) -> {
        if (left != oldLeft
            || right != oldRight
            || top != oldTop
            || bottom != oldBottom) {
            // The playerView's bounds changed, update the source hint rect to
            // reflect its new bounds.
            final Rect sourceRectHint = new Rect();
            playerView.getGlobalVisibleRect(sourceRectHint);
            setPictureInPictureParams(
                new PictureInPictureParams.Builder()
                    .setSourceRectHint(sourceRectHint)
                    .build());
        }
    });

Tắt tính năng đổi kích thước liền mạch cho nội dung không phải video

Android 12 bổ sung cờ setSeamlessResizeEnabled, cung cấp ảnh động mờ dần trên nhiều màn hình khi đổi kích thước nội dung không phải video trong cửa sổ PiP. Trước đây, việc đổi kích thước nội dung không phải video trong cửa sổ PiP có thể tạo ra các thành phần hình ảnh khó hiểu.

Cách tắt tính năng đổi kích thước liền mạch cho nội dung không phải video:

Kotlin

setPictureInPictureParams(PictureInPictureParams.Builder()
    .setSeamlessResizeEnabled(false)
    .build())

Java

setPictureInPictureParams(new PictureInPictureParams.Builder()
    .setSeamlessResizeEnabled(false)
    .build());

Xử lý giao diện người dùng trong chế độ PiP

Khi hoạt động chuyển sang hoặc thoát khỏi chế độ Hình trong hình (PiP), hệ thống sẽ gọi Activity.onPictureInPictureModeChanged() hoặc Fragment.onPictureInPictureModeChanged().

Android 15 ra mắt các thay đổi đảm bảo quá trình chuyển đổi mượt mà hơn khi chuyển sang chế độ PiP. Điều này có lợi cho các ứng dụng có các thành phần trên giao diện người dùng được phủ lên giao diện người dùng chính, sau đó chuyển sang PiP.

Nhà phát triển sử dụng lệnh gọi lại onPictureInPictureModeChanged() để xác định logic bật/tắt chế độ hiển thị của các thành phần giao diện người dùng được phủ lên. Lệnh gọi lại này được kích hoạt khi ảnh động vào hoặc thoát PiP hoàn tất. Kể từ Android 15, lớp PictureInPictureUiState sẽ bao gồm một trạng thái mới.

Với trạng thái giao diện người dùng mới này, các ứng dụng nhắm đến Android 15 sẽ thấy lệnh gọi lại Activity#onPictureInPictureUiStateChanged() được gọi bằng isTransitioningToPip() ngay khi ảnh động trong Hình trong hình bắt đầu. Có nhiều thành phần trên giao diện người dùng không liên quan đến ứng dụng khi ứng dụng ở chế độ PiP, ví dụ: thành phần hiển thị hoặc bố cục chứa thông tin như đề xuất, video sắp tới, điểm xếp hạng và tiêu đề. Khi ứng dụng chuyển sang chế độ PiP, hãy sử dụng lệnh gọi lại onPictureInPictureUiStateChanged() để ẩn các thành phần trên giao diện người dùng này. Khi ứng dụng chuyển sang chế độ toàn màn hình từ cửa sổ Hình trong hình, hãy sử dụng lệnh gọi lại onPictureInPictureModeChanged() để hiện các phần tử này, như trong các ví dụ sau:

Kotlin

override fun onPictureInPictureUiStateChanged(pipState: PictureInPictureUiState) {
        if (pipState.isTransitioningToPip()) {
          // Hide UI elements.
        }
    }

Java

@Override
public void onPictureInPictureUiStateChanged(PictureInPictureUiState pipState) {
        if (pipState.isTransitioningToPip()) {
          // Hide UI elements.
        }
    }

Kotlin

override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {
        if (isInPictureInPictureMode) {
          // Unhide UI elements.
        }
    }

Java

@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
        if (isInPictureInPictureMode) {
          // Unhide UI elements.
        }
    }

Nút bật/tắt chế độ hiển thị nhanh các thành phần giao diện người dùng không liên quan (đối với cửa sổ PiP) giúp đảm bảo ảnh động chuyển đổi PiP mượt mà và không nhấp nháy.

Ghi đè các lệnh gọi lại này để vẽ lại các thành phần giao diện người dùng của hoạt động. Xin lưu ý rằng ở chế độ PiP, hoạt động của bạn xuất hiện trong một cửa sổ nhỏ. Người dùng không thể tương tác với các thành phần trên giao diện người dùng của ứng dụng khi ứng dụng đó đang ở chế độ PiP và có thể khó nhìn thấy thông tin chi tiết về các thành phần nhỏ trên giao diện người dùng. Các hoạt động phát video trên giao diện người dùng ở mức tối thiểu sẽ đem lại trải nghiệm người dùng tốt nhất.

Nếu ứng dụng của bạn cần cung cấp các hành động tuỳ chỉnh cho PiP, hãy xem phần Thêm chế độ điều khiển trên trang này. Xoá các thành phần giao diện người dùng khác trước khi hoạt động chuyển sang chế độ PiP và khôi phục các thành phần đó khi hoạt động chuyển sang chế độ toàn màn hình trở lại.

Thêm chế độ điều khiển

Cửa sổ PiP có thể hiện các tuỳ chọn điều khiển khi người dùng mở trình đơn của cửa sổ (bằng cách nhấn vào cửa sổ trên thiết bị di động hoặc chọn menu (trình đơn) trong điều khiển từ xa của TV).

Nếu ứng dụng có một phiên hoạt động nội dung đa phương tiện đang hoạt động, thì các nút điều khiển phát, tạm dừng, tiếp theo và trước đó sẽ xuất hiện.

Bạn cũng có thể chỉ định rõ các hành động tuỳ chỉnh bằng cách tạo PictureInPictureParams bằng PictureInPictureParams.Builder.setActions() trước khi chuyển sang chế độ PiP và truyền các thông số khi bạn chuyển sang chế độ PiP bằng cách sử dụng enterPictureInPictureMode(android.app.PictureInPictureParams) hoặc setPictureInPictureParams(android.app.PictureInPictureParams). Hãy thận trọng. Nếu cố thêm nhiều hơn getMaxNumPictureInPictureActions(), bạn sẽ chỉ nhận được số lượng tối đa.

Tiếp tục phát video khi ở chế độ PiP

Khi hoạt động của bạn chuyển sang chế độ PiP, hệ thống sẽ đặt hoạt động ở trạng thái tạm dừng và gọi phương thức onPause() của hoạt động đó. Bạn không nên tạm dừng phát video mà hãy tiếp tục phát nếu hoạt động đó bị tạm dừng khi chuyển sang chế độ PiP.

Với Android 7.0 trở lên, bạn nên tạm dừng và tiếp tục phát video khi hệ thống gọi onStop()onStart() của hoạt động của bạn. Bằng cách này, bạn có thể tránh phải kiểm tra xem ứng dụng của mình có đang ở chế độ PiP không trên onPause() hay không và tiếp tục phát một cách rõ ràng.

Nếu bạn chưa đặt cờ setAutoEnterEnabled thành true và cần tạm dừng phát trong quá trình triển khai onPause(), hãy kiểm tra chế độ PiP bằng cách gọi isInPictureInPictureMode() và xử lý chế độ phát sao cho phù hợp. Ví dụ:

Kotlin

override fun onPause() {
    super.onPause()
    // If called while in PiP mode, do not pause playback.
    if (isInPictureInPictureMode) {
        // Continue playback.
    } else {
        // Use existing playback logic for paused activity behavior.
    }
}

Java

@Override
public void onPause() {
    // If called while in PiP mode, do not pause playback.
    if (isInPictureInPictureMode()) {
        // Continue playback.
        ...
    } else {
        // Use existing playback logic for paused activity behavior.
        ...
    }
}

Khi hoạt động của bạn chuyển từ chế độ PiP trở về chế độ toàn màn hình, hệ thống sẽ tiếp tục hoạt động và gọi phương thức onResume().

Sử dụng một hoạt động phát duy nhất cho tính năng PiP

Trong ứng dụng của bạn, người dùng có thể chọn một video mới khi duyệt xem nội dung trên màn hình chính, trong khi một hoạt động phát video đang ở chế độ PiP. Hãy phát video mới trong hoạt động phát hiện có ở chế độ toàn màn hình thay vì chạy hoạt động mới có thể khiến người dùng nhầm lẫn.

Để đảm bảo sử dụng một hoạt động đơn cho các yêu cầu phát video và chuyển sang hoặc tắt chế độ PiP nếu cần, hãy đặt android:launchMode của hoạt động thành singleTask trong tệp kê khai:

<activity android:name="VideoActivity"
    ...
    android:supportsPictureInPicture="true"
    android:launchMode="singleTask"
    ...

Trong hoạt động của bạn, hãy ghi đè onNewIntent() và xử lý video mới, dừng mọi hoạt động phát video hiện có, nếu cần.

Các phương pháp hay nhất

Bạn có thể tắt tính năng PiP trên các thiết bị có dung lượng RAM thấp. Trước khi ứng dụng của bạn sử dụng tính năng PiP, hãy kiểm tra để đảm bảo rằng tính năng này có sẵn bằng cách gọi hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE).

PiP được sử dụng cho các hoạt động phát video toàn màn hình. Khi chuyển đổi hoạt động sang chế độ PiP, hãy tránh hiện nội dung nào khác ngoài nội dung video. Theo dõi hoạt động của bạn khi chuyển sang chế độ PiP và ẩn các thành phần trên giao diện người dùng, như mô tả trong bài viết Xử lý giao diện người dùng trong chế độ PiP.

Khi ở một chế độ PiP, theo mặc định, hoạt động sẽ không thu thập được quyền phát đầu vào. Để nhận sự kiện đầu vào khi ở chế độ PiP, hãy sử dụng MediaSession.setCallback(). Để biết thêm thông tin về cách sử dụng setCallback(), hãy xem phần Hiện thẻ Phát hiện nhạc.

Khi ứng dụng của bạn ở chế độ PiP, việc phát video trong cửa sổ PiP có thể gây ra sự can thiệp âm thanh với một ứng dụng khác, chẳng hạn như ứng dụng phát nhạc hoặc ứng dụng tìm kiếm bằng giọng nói. Để tránh điều này, hãy yêu cầu quyền phát âm thanh khi bạn bắt đầu phát video và xử lý thông báo thay đổi quyền phát âm thanh, như mô tả trong phần Quản lý quyền phát âm thanh. Nếu bạn nhận được thông báo về việc mất quyền phát âm thanh khi ở chế độ PiP, hãy tạm dừng hoặc dừng phát video.

Khi ứng dụng của bạn sắp chuyển sang chế độ PiP, hãy lưu ý rằng chỉ hoạt động hàng đầu mới được chuyển vào chế độ hình trong hình. Trong một số trường hợp như trên các thiết bị nhiều cửa sổ, có thể hoạt động bên dưới sẽ xuất hiện và hiển thị lại cùng với hoạt động PiP. Bạn nên xử lý trường hợp này một cách phù hợp, bao gồm cả hoạt động dưới đây khi nhận được lệnh gọi lại onResume() hoặc onPause(). Cũng có thể người dùng có thể tương tác với hoạt động. Ví dụ: nếu bạn có một hoạt động danh sách video đang hiển thị và hoạt động phát video trong chế độ PiP, có thể người dùng sẽ chọn video mới trong danh sách và hoạt động PiP phải được cập nhật tương ứng.

Các đoạn mã mẫu khác

Để tải ứng dụng mẫu viết bằng Kotlin, hãy xem phần Mẫu PictureInPicture cho Android (Kotlin).