Pemburaman jendela

Di Android 12, API publik tersedia untuk mengimplementasikan efek pemburaman jendela, seperti pemburaman latar belakang dan pemburaman.

Blur jendela, atau blur lintas jendela, digunakan untuk memburamkan layar di belakang jendela tertentu. Ada dua jenis jendela blur yang dapat digunakan untuk mencapai berbagai efek visual:

  • Blur latar belakang memungkinkan Anda membuat jendela dengan latar belakang yang diburamkan, sehingga menciptakan efek kaca buram.

  • Blur di belakang memungkinkan Anda membuat blur seluruh layar di belakang jendela (dialog), sehingga menciptakan efek depth of field.

Kedua efek tersebut dapat digunakan secara terpisah atau digabungkan, seperti yang ditunjukkan pada gambar berikut:

hanya blur latar belakang

a

hanya blur di belakang

b

blur behind dan blur latar belakang

k

Gambar 1. Hanya blur latar belakang (a), hanya blur di belakang (b), blur latar belakang dan blur di belakang (c)

Fitur pemburaman jendela berfungsi di seluruh jendela, yang berarti juga berfungsi saat ada aplikasi lain di belakang jendela Anda. Efek ini tidak sama dengan efek render blur, yang memburamkan konten di dalam jendela yang sama. Jendela blur berguna untuk dialog, sheet bawah, dan jendela mengambang lainnya.

Implementasi

Developer aplikasi

Developer aplikasi harus menyediakan radius blur untuk membuat efek buram. Radius blur mengontrol seberapa rapat blur, yaitu, semakin tinggi radius, semakin padat blur. Blur 0 px berarti tidak ada blur. Untuk blur latar belakang, radius 20 px menciptakan efek kedalaman bidang yang baik, sedangkan radius blur latar belakang 80 px membuat efek kaca buram yang baik. Hindari radius buram yang lebih tinggi dari 150 px, karena akan memengaruhi performa secara signifikan.

Untuk mendapatkan efek blur yang diinginkan dan meningkatkan keterbacaan, pilih nilai radius blur yang dilengkapi dengan lapisan warna transparan.

Blur latar belakang

Gunakan pemburaman latar belakang pada jendela mengambang untuk membuat efek latar belakang jendela yang merupakan gambar buram dari konten yang mendasarinya. Untuk menambahkan latar belakang buram untuk jendela, lakukan hal berikut:

  1. Panggil Window#setBackgroundBlurRadius(int) untuk menetapkan radius pemburaman latar belakang. Atau, di tema jendela, tetapkan R.attr.windowBackgroundBlurRadius.

  2. Tetapkan R.attr.windowIsTranslucent ke true untuk membuat jendela menjadi buram. Blur digambar di bawah permukaan jendela, sehingga jendela harus transparan agar blur terlihat.

  3. Secara opsional, panggil Window#setBackgroundDrawableResource(int) untuk menambahkan drawable latar belakang jendela persegi panjang dengan warna transparan. Atau, di tema jendela, tetapkan R.attr.windowBackground.

  4. Untuk jendela dengan sudut membulat, tentukan sudut membulat untuk area yang diburamkan dengan menetapkan ShapeDrawable dengan sudut membulat sebagai drawable latar belakang jendela.

  5. Menangani status blur aktif dan nonaktif. Lihat bagian Panduan menggunakan pemburaman jendela di aplikasi untuk informasi selengkapnya.

Buramkan di belakang

Blur di belakang akan memburamkan seluruh layar di belakang jendela. Efek ini digunakan untuk mengarahkan perhatian pengguna ke konten jendela dengan memburamkan apa pun pada layar di belakang jendela.

Untuk memburamkan konten di belakang jendela, ikuti langkah-langkah berikut:

  1. Tambahkan FLAG_BLUR_BEHIND ke flag jendela, untuk mengaktifkan pemburaman di belakang. Atau, di tema jendela, tetapkan R.attr.windowBlurBehindEnabled.

  2. Panggil WindowManager.LayoutParams#setBlurBehindRadius untuk menetapkan blur di belakang radius. Atau, di tema jendela, tetapkan R.attr.windowBlurBehindRadius.

  3. Secara opsional, pilih jumlah redup yang saling melengkapi.

  4. Menangani status blur aktif dan nonaktif. Lihat bagian Panduan menggunakan pemburaman jendela di aplikasi untuk informasi selengkapnya.

Panduan untuk menggunakan pemburaman jendela di aplikasi

Dukungan untuk window blur bergantung pada hal berikut:

  • Versi Android: API pemburaman jendela hanya tersedia di Android 12 dan yang lebih tinggi. Periksa SDK perangkat untuk mengetahui versi Android.

  • Performa grafis: Perangkat dengan GPU berperforma lebih rendah mungkin memilih untuk tidak mendukung pemburaman jendela.

  • Status sistem: Server sistem mungkin menonaktifkan pemburaman jendela untuk sementara saat runtime, misalnya, selama mode hemat baterai, saat memutar jenis konten video tertentu atau karena penggantian developer.

Agar aplikasi Anda kompatibel di seluruh versi Android, perangkat, dan status sistem, ikuti panduan berikut:

  • Tambahkan pemroses melalui WindowManager#addCrossWindowBlurEnabledListener, untuk memberi tahu Anda saat pemburaman jendela diaktifkan atau dinonaktifkan. Selain itu, gunakan WindowManager#isCrossWindowBlurEnabled untuk mengkueri apakah jendela blur saat ini diaktifkan.

  • Implementasikan dua versi untuk latar belakang jendela, untuk mengakomodasi status pemburaman jendela yang diaktifkan atau dinonaktifkan.

    Saat pemburaman diaktifkan, latar belakang jendela harus transparan agar blur terlihat. Dalam status ini, saat pemburaman dinonaktifkan, konten jendela langsung tumpang-tindih dengan konten jendela yang mendasarinya, sehingga jendela yang tumpang-tindih menjadi kurang jelas. Untuk menghindari efek ini, saat pemburaman jendela dinonaktifkan, sesuaikan UI aplikasi sebagai berikut:

    • Untuk pemburaman latar belakang, tingkatkan alfa drawable latar belakang jendela, sehingga lebih buram.

    • Untuk bagian belakang yang buram, tambahkan lapisan redup dengan tingkat redup yang lebih tinggi.

Contoh pemburaman di belakang dan pemburaman latar belakang

Bagian ini memberikan contoh kerja aktivitas yang menggunakan blur di belakang dan blur latar belakang.

Contoh MainActivity.java berikut adalah dialog dengan radius buram di belakang layar 20 px dan radius blur latar belakang 80 px. Drawable ini memiliki sudut membulat, yang ditentukan dalam xml di drawable latar belakang jendela. Alat ini menangani versi Android yang berbeda, perangkat yang berbeda (yang berpotensi tidak mendukung pemburaman jendela), dan pemburaman runtime yang diaktifkan atau dinonaktifkan. Ini memastikan bahwa konten dialog dapat dibaca dalam salah satu kondisi tersebut dengan menyesuaikan alfa drawable latar belakang jendela dan jumlah peredupan jendela.

public class MainActivity extends Activity {

    private final int mBackgroundBlurRadius = 80;
    private final int mBlurBehindRadius = 20;

    // We set a different dim amount depending on whether window blur is enabled or disabled
    private final float mDimAmountWithBlur = 0.1f;
    private final float mDimAmountNoBlur = 0.4f;

    // We set a different alpha depending on whether window blur is enabled or disabled
    private final int mWindowBackgroundAlphaWithBlur = 170;
    private final int mWindowBackgroundAlphaNoBlur = 255;

    // Use a rectangular shape drawable for the window background. The outline of this drawable
    // dictates the shape and rounded corners for the window background blur area.
    private Drawable mWindowBackgroundDrawable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWindowBackgroundDrawable = getDrawable(R.drawable.window_background);
        getWindow().setBackgroundDrawable(mWindowBackgroundDrawable);

        if (buildIsAtLeastS()) {
            // Enable blur behind. This can also be done in xml with R.attr#windowBlurBehindEnabled
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);

            // Register a listener to adjust window UI whenever window blurs are enabled/disabled
            setupWindowBlurListener();
        } else {
            // Window blurs are not available prior to Android S
            updateWindowForBlurs(false /* blursEnabled */);
        }

        // Enable dim. This can also be done in xml, see R.attr#backgroundDimEnabled
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    }

    /**
     * Set up a window blur listener.
     *
     * Window blurs might be disabled at runtime in response to user preferences or system states
     * (e.g. battery saving mode). WindowManager#addCrossWindowBlurEnabledListener allows to
     * listen for when that happens. In that callback we adjust the UI to account for the
     * added/missing window blurs.
     *
     * For the window background blur we adjust the window background drawable alpha:
     *     - lower when window blurs are enabled to make the blur visible through the window
     *       background drawable
     *     - higher when window blurs are disabled to ensure that the window contents are readable
     *
     * For window blur behind we adjust the dim amount:
     *     - higher when window blurs are disabled - the dim creates a depth of field effect,
     *       bringing the user's attention to the dialog window
     *     - lower when window blurs are enabled - no need for a high alpha, the blur behind is
     *       enough to create a depth of field effect
     */
    @RequiresApi(api = Build.VERSION_CODES.S)
    private void setupWindowBlurListener() {
        Consumer<Boolean> windowBlurEnabledListener = this::updateWindowForBlurs;
        getWindow().getDecorView().addOnAttachStateChangeListener(
                new View.OnAttachStateChangeListener() {
                    @Override
                    public void onViewAttachedToWindow(View v) {
                        getWindowManager().addCrossWindowBlurEnabledListener(
                                windowBlurEnabledListener);
                    }

                    @Override
                    public void onViewDetachedFromWindow(View v) {
                        getWindowManager().removeCrossWindowBlurEnabledListener(
                                windowBlurEnabledListener);
                    }
                });
    }

    private void updateWindowForBlurs(boolean blursEnabled) {
        mWindowBackgroundDrawable.setAlpha(blursEnabled && mBackgroundBlurRadius > 0 ?
                mWindowBackgroundAlphaWithBlur : mWindowBackgroundAlphaNoBlur);
        getWindow().setDimAmount(blursEnabled && mBlurBehindRadius > 0 ?
                mDimAmountWithBlur : mDimAmountNoBlur);

        if (buildIsAtLeastS()) {
            // Set the window background blur and blur behind radii
            getWindow().setBackgroundBlurRadius(mBackgroundBlurRadius);
            getWindow().getAttributes().setBlurBehindRadius(mBlurBehindRadius);
            getWindow().setAttributes(getWindow().getAttributes());
        }
    }

    private static boolean buildIsAtLeastS() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
    }
}

Untuk membuat sudut membulat bagi jendela, kita tentukan latar belakang jendela di res/drawable/window_background.xml sebagai ShapeDrawable dengan sudut membulat dengan radius 20 dp seperti berikut:

<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
    <corners android:radius="20dp"/>
    <solid android:color="#AAAAAA"/>
</shape>

Jendela memburamkan konten jendela di bawah aktivitas. Gambar yang menjadi blur digambar di bawah jendela aktivitas ini, sehingga jendela aktivitas harus transparan agar pemburaman terlihat. Untuk membuat jendela transparan, kita tetapkan R.attr.windowIsTranslucent dalam tema aktivitas sebagai berikut:

<style name="Theme.BlurryDialog" parent="Theme.MaterialComponents.Dialog">
    <item name="android:windowIsTranslucent">true</item>
</style>

OEM dan partner

Agar jendela menjadi blur di perangkat, OEM harus mendeklarasikan bahwa perangkat mendukung pemburaman jendela.

Untuk memeriksa apakah perangkat Anda dapat mendukung pemburaman jendela, lakukan hal berikut:

  • Pastikan perangkat dapat menangani beban GPU tambahan. Perangkat kelas bawah mungkin tidak dapat menangani beban tambahan, yang dapat menyebabkan frame terputus. Hanya aktifkan pemburaman jendela di perangkat yang diuji dengan daya GPU yang memadai.

  • Jika Anda memiliki mesin render kustom, pastikan mesin render Anda mengimplementasikan logika pemburaman. Mesin render Android 12 default mengimplementasikan logika pemburaman di BlurFilter.cpp.

Setelah memastikan bahwa perangkat dapat mendukung pemburaman jendela, tetapkan surface flinger berikut sysprop:

PRODUCT_VENDOR_PROPERTIES += \
       ro.surface_flinger.supports_background_blur=1

Validasi

Untuk memvalidasi bahwa jendela aplikasi Anda memiliki penanganan yang tepat saat beralih antara status blur diaktifkan dan blur, ikuti langkah-langkah berikut:

  1. Buka UI yang memiliki pemburaman.

  2. Aktifkan atau nonaktifkan pemburaman jendela dengan mengaktifkan dan menonaktifkan pemburaman jendela.

  3. Verifikasi bahwa UI jendela berubah ke dan dari status buram seperti yang diharapkan.

Mengaktifkan dan menonaktifkan blur jendela

Untuk menguji cara UI jendela dirender dengan efek blur jendela, aktifkan atau nonaktifkan blur menggunakan salah satu metode berikut:

  • Dari Opsi Developer:

    Setelan -> Sistem -> Opsi developer -> Rendering dengan akselerasi hardware -> Izinkan pemburaman tingkat jendela

  • Dari terminal di perangkat yang di-root:

    adb shell wm disable-blur 1 # 1 disables window blurs, 0 allows them

Untuk memeriksa apakah perangkat Android 12+ Anda mendukung pemburaman jendela dan apakah pemburaman jendela saat ini diaktifkan, jalankan adb shell wm disable-blur di perangkat yang di-root.

Pemecahan masalah

Gunakan informasi berikut sebagai panduan untuk memecahkan masalah selama validasi.

Tidak ada pemburaman yang digambar

  • Pastikan pemburaman saat ini diaktifkan dan hardware Anda mendukungnya. Lihat Mengaktifkan dan menonaktifkan pemburaman jendela.

  • Pastikan Anda menyetel warna latar belakang jendela yang transparan. Warna latar belakang jendela buram akan menyembunyikan area yang diburamkan.

Perangkat pengujian tidak mendukung pemburaman jendela

  • Uji aplikasi Anda di emulator Android 12. Untuk menyiapkan emulator Android, lihat Menyiapkan emulator Android. Setiap perangkat virtual Android yang Anda buat dengan emulator akan mendukung blur jendela.

Tidak ada sudut membulat

Memperbarui opsi developer tidak mengaktifkan pemburaman

  • Periksa apakah perangkat dalam mode hemat baterai atau menggunakan multimedia tunneling. Di beberapa perangkat TV, pemburaman jendela juga dapat dinonaktifkan selama pemutaran video.

Blur latar belakang digambar dalam layar penuh, bukan dalam batas jendela

Update dari pemroses tidak diterapkan di layar

  • Update pemroses mungkin diterapkan ke instance jendela lama. Periksa apakah jendela dihancurkan dan dibuat ulang dengan update pemroses yang tepat.