Status Update
Comments
cl...@google.com <cl...@google.com>
gu...@gmail.com <gu...@gmail.com> #2
1. Have you saw crash in real device or only in simulators?
2. Do you use dynamic feature for language ID?
il...@gmail.com <il...@gmail.com> #3
Tested on Android 12 Emulator with custom executor, but cannot repro this issue.
me...@gmail.com <me...@gmail.com> #4
-
Second crash in the description is from a real device. Experienced it myself on two different Xiaomi phones, plus lots of crashes from users in the Google Play console.
-
Dynamic features are not used in the application.
As a wild guess, I have downgraded build tools from 31.0.0 to 30.0.3, compileSdk from 31 to 30, and moved all work with Language ID to the service in a separate process (just to be sure that crash can kill secondary process instead of main). This combination is in beta for 2 days by now and I don't see any SIGSEGV crashes.
co...@gmail.com <co...@gmail.com> #5
Hmm, I feel the crash might be something related to separate/secondary process.
I also changed compileSdk and targetSDK to 31 but still cannot repro this issue.
ja...@gmail.com <ja...@gmail.com> #6
On the contrary, there was no separate process before, when crashes started.
In the new build (with the aforementioned changes) I can see SIGSEGV crash, but only one instead of dozens and it has a bit different backtrace:
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR)
liblanguage_id_jni.so (offset 0x11e000)
backtrace:
#00 pc 000000000003c7c0 /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/split_config.arm64_v8a.apk!lib/arm64-v8a/liblanguage_id_jni.so (offset 0x11e000)
#00 pc 000000000003b960 /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/split_config.arm64_v8a.apk!lib/arm64-v8a/liblanguage_id_jni.so (offset 0x11e000)
#00 pc 000000000003bb48 /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/split_config.arm64_v8a.apk!lib/arm64-v8a/liblanguage_id_jni.so (offset 0x11e000)
#00 pc 000000000003bafc /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/split_config.arm64_v8a.apk!lib/arm64-v8a/liblanguage_id_jni.so (offset 0x11e000)
#00 pc 0000000000036c98 /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/split_config.arm64_v8a.apk!lib/arm64-v8a/liblanguage_id_jni.so (offset 0x11e000)
#00 pc 0000000000032714 /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/split_config.arm64_v8a.apk!lib/arm64-v8a/liblanguage_id_jni.so (offset 0x11e000)
#00 pc 0000000000031cac /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/split_config.arm64_v8a.apk!lib/arm64-v8a/liblanguage_id_jni.so (offset 0x11e000)
#00 pc 0000000000057438 /data/app/azagroup.reedy-mF7zTu2bv_ELlbFArwNgqA==/oat/arm64/base.odex (offset 0x57000)
sa...@rapido.bike <sa...@rapido.bike> #7
FYI, ML Kit launched a new language ID SDK in the latest release, which uses a new language ID model.
Could you try the new SDK version(17.0.0) to check if you can still repro this native crash? Thanks!
ro...@gmail.com <ro...@gmail.com> #8
Thank you, I'll try it and check.
za...@gmail.com <za...@gmail.com> #9
Hello. I have similar experience.
- I'm using mlkit-language 16.1.1
- I didnot meet this error until using AGP 4.2
- I can get this error since using AGP 7.0
- This error raised on Release build only(minimized by R8)
- This error raised without obfuscation.
ba...@gmail.com <ba...@gmail.com> #11
I created reproducible project.
$ git clone https://github.com/ganadist/VersionCodeDemo -b mlkit_agp7 mlkit_agp7
$ cd mlkit_agp7
$ ./gradlew :app:pPRUA
$ adb install app/build/outputs/universal_apk/productionRelease/app-production-release-universal.apk
$ adb shell am start -n com.example.myapplication/.MainActivity
$ adb logcat -b crash -d
10-19 19:41:49.844 17810 17810 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x7acf9d733c in tid 17810 (e.myapplication), pid 17810 (e.myapplication)
10-19 19:41:50.473 17849 17849 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
10-19 19:41:50.473 17849 17849 F DEBUG : Build fingerprint: 'google/crosshatch/crosshatch:12/SPB5.210812.002/7671067:user/release-keys'
10-19 19:41:50.473 17849 17849 F DEBUG : Revision: 'MP1.0'
10-19 19:41:50.473 17849 17849 F DEBUG : ABI: 'arm64'
10-19 19:41:50.473 17849 17849 F DEBUG : Timestamp: 2021-10-19 19:41:49.903736988+0900
10-19 19:41:50.473 17849 17849 F DEBUG : Process uptime: 0s
10-19 19:41:50.473 17849 17849 F DEBUG : Cmdline: com.example.myapplication
10-19 19:41:50.474 17849 17849 F DEBUG : pid: 17810, tid: 17810, name: e.myapplication >>> com.example.myapplication <<<
10-19 19:41:50.474 17849 17849 F DEBUG : uid: 10240
10-19 19:41:50.474 17849 17849 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x7acf9d733c
10-19 19:41:50.474 17849 17849 F DEBUG : x0 0000000000000000 x1 00000000000008fc x2 0000007a76760c71 x3 0000000000000000
10-19 19:41:50.474 17849 17849 F DEBUG : x4 0000000000000010 x5 0000007ba4db49d0 x6 0000007b34dc3680 x7 3de38e3900000608
10-19 19:41:50.474 17849 17849 F DEBUG : x8 0000007bb4dbedf0 x9 0000007acf9db2aa x10 0000000000000000 x11 0000007acf9d6640
10-19 19:41:50.474 17849 17849 F DEBUG : x12 0000000000000009 x13 0000000000000000 x14 0000000000000061 x15 00000000ebad6a89
10-19 19:41:50.474 17849 17849 F DEBUG : x16 0000007a767cfef8 x17 0000007d9a564b40 x18 0000007da3830000 x19 0000007feaf56a08
10-19 19:41:50.474 17849 17849 F DEBUG : x20 0000000000000000 x21 0000007ba4da50b0 x22 0000007bb4dbedf0 x23 0000007ba4da50b8
10-19 19:41:50.474 17849 17849 F DEBUG : x24 0000000000000009 x25 000000000000067e x26 0000000000000012 x27 0000000000000008
10-19 19:41:50.474 17849 17849 F DEBUG : x28 0000007b64dc8440 x29 0000000000000000
10-19 19:41:50.474 17849 17849 F DEBUG : lr 0000007a7678a964 sp 0000007feaf56810 pc 0000007a7678b7c0 pst 0000000060000000
10-19 19:41:50.474 17849 17849 F DEBUG : backtrace:
10-19 19:41:50.474 17849 17849 F DEBUG : #00 pc 000000000003c7c0 /data/app/~~mHaMq-e9ocbm9UfYnkCGkQ==/com.example.myapplication-HgG9vkluwDDO1K78-Vzr0A==/lib/arm64/liblanguage_id_jni.so (BuildId: 859ec0ec2000a39e6ae8ed42e1704f46)
10-19 19:41:50.474 17849 17849 F DEBUG : #01 pc 000000000003b960 /data/app/~~mHaMq-e9ocbm9UfYnkCGkQ==/com.example.myapplication-HgG9vkluwDDO1K78-Vzr0A==/lib/arm64/liblanguage_id_jni.so (BuildId: 859ec0ec2000a39e6ae8ed42e1704f46)
10-19 19:41:50.474 17849 17849 F DEBUG : #02 pc 000000000003bb48 /data/app/~~mHaMq-e9ocbm9UfYnkCGkQ==/com.example.myapplication-HgG9vkluwDDO1K78-Vzr0A==/lib/arm64/liblanguage_id_jni.so (BuildId: 859ec0ec2000a39e6ae8ed42e1704f46)
10-19 19:41:50.474 17849 17849 F DEBUG : #03 pc 000000000003bafc /data/app/~~mHaMq-e9ocbm9UfYnkCGkQ==/com.example.myapplication-HgG9vkluwDDO1K78-Vzr0A==/lib/arm64/liblanguage_id_jni.so (BuildId: 859ec0ec2000a39e6ae8ed42e1704f46)
10-19 19:41:50.474 17849 17849 F DEBUG : #04 pc 0000000000036c98 /data/app/~~mHaMq-e9ocbm9UfYnkCGkQ==/com.example.myapplication-HgG9vkluwDDO1K78-Vzr0A==/lib/arm64/liblanguage_id_jni.so (BuildId: 859ec0ec2000a39e6ae8ed42e1704f46)
10-19 19:41:50.474 17849 17849 F DEBUG : #05 pc 00000000000324a4 /data/app/~~mHaMq-e9ocbm9UfYnkCGkQ==/com.example.myapplication-HgG9vkluwDDO1K78-Vzr0A==/lib/arm64/liblanguage_id_jni.so (BuildId: 859ec0ec2000a39e6ae8ed42e1704f46)
10-19 19:41:50.474 17849 17849 F DEBUG : #06 pc 0000000000031b5c /data/app/~~mHaMq-e9ocbm9UfYnkCGkQ==/com.example.myapplication-HgG9vkluwDDO1K78-Vzr0A==/lib/arm64/liblanguage_id_jni.so (Java_com_google_mlkit_nl_languageid_internal_LanguageIdentificationJni_nativeIdentifyLanguage+100) (BuildId: 859ec0ec2000a39e6ae8ed42e1704f46)
But after downgrade to AGP 4.2, crash is not reproducible.
$ git clone https://github.com/ganadist/VersionCodeDemo -b mlkit_agp42 mlkit_agp42
$ cd mlkit_agp42
$ ./gradlew :app:pPRUA
$ adb install app/build/outputs/universal_apk/productionRelease/app-production-release-universal.apk
$ adb shell am start -n com.example.myapplication/.MainActivity
Also, I tried to disable
$ git clone https://github.com/ganadist/VersionCodeDemo -b mlkit_agp7_r8_disable_inline_optimizer mlkit_agp7_r8
$ cd mlkit_agp7_r8
$ ./gradlew :app:pPRUA
$ adb install app/build/outputs/universal_apk/productionRelease/app-production-release-universal.apk
$ adb shell am start -n com.example.myapplication/.MainActivity
pr...@gmail.com <pr...@gmail.com> #12
I tried the repro steps but got a NPE when I run ./gradlew :app:pPRUA
FAILURE: Build failed with an exception.
* What went wrong:
java.lang.NullPointerException
> java.lang.NullPointerException (no error message)
Could you also check if this is reproducible on 17.0.0
or 17.0.1
? If yes, could you attach the full log that I can take a look? Thanks!
ma...@gmail.com <ma...@gmail.com> #13
Here are gradle build scan logs for each branches.
All builds were clean build, and disabled build cache.
- mlkit_agp7 :
https://scans.gradle.com/s/qrymdqfzwokbq - mlkit_agp42 :
https://scans.gradle.com/s/b6644hzfyfhaw - mlkit_agp7_r8_disable_inline_optimizer :
https://scans.gradle.com/s/c6h5hy2nxod4u
Also, I pushed to update MLKit Language Id version 17.0.1 on
And here is crash log after apply 17.0.1
You can see that BuildId
of liblanguage_id_l2c_jni.so
was changed from 859ec0ec2000a39e6ae8ed42e1704f46
to be6e59455cc10135330c93acdebfc121
10-20 03:07:24.522 24587 24628 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x7acf995426 in tid 24628 (pool-3-thread-3), pid 24587 (e.myapplication)
10-20 03:07:25.190 24710 24710 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
10-20 03:07:25.190 24710 24710 F DEBUG : Build fingerprint: 'google/crosshatch/crosshatch:12/SPB5.210812.002/7671067:user/release-keys'
10-20 03:07:25.190 24710 24710 F DEBUG : Revision: 'MP1.0'
10-20 03:07:25.190 24710 24710 F DEBUG : ABI: 'arm64'
10-20 03:07:25.190 24710 24710 F DEBUG : Timestamp: 2021-10-20 03:07:24.583346246+0900
10-20 03:07:25.190 24710 24710 F DEBUG : Process uptime: 0s
10-20 03:07:25.190 24710 24710 F DEBUG : Cmdline: com.example.myapplication
10-20 03:07:25.190 24710 24710 F DEBUG : pid: 24587, tid: 24628, name: pool-3-thread-3 >>> com.example.myapplication <<<
10-20 03:07:25.190 24710 24710 F DEBUG : uid: 10240
10-20 03:07:25.190 24710 24710 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x7acf995426
10-20 03:07:25.190 24710 24710 F DEBUG : x0 0000007b54da9d30 x1 0000007d9a5fe7cc x2 0000000000000000 x3 0000000000000010
10-20 03:07:25.190 24710 24710 F DEBUG : x4 0000000000000000 x5 0000007c34dbc79c x6 0000002f0000083b x7 000003c300002dd5
10-20 03:07:25.190 24710 24710 F DEBUG : x8 0000000000000001 x9 0000000000000004 x10 0000000000000010 x11 0000000000000000
10-20 03:07:25.190 24710 24710 F DEBUG : x12 0000000000000000 x13 000000000000217e x14 0000007acf9932a8 x15 000000000000217e
10-20 03:07:25.190 24710 24710 F DEBUG : x16 0000000000000000 x17 0000007d9a564c78 x18 0000007a6ef18000 x19 0000007c34dbc580
10-20 03:07:25.190 24710 24710 F DEBUG : x20 0000007ca4dc7170 x21 0000007ca4dc7800 x22 0000007ca4dc71e0 x23 0000000000000000
10-20 03:07:25.190 24710 24710 F DEBUG : x24 0000000000000018 x25 0000000000000007 x26 0000000000000006 x27 0000000000000004
10-20 03:07:25.190 24710 24710 F DEBUG : x28 0000007ca4dc7090 x29 0000007cb4da9940
10-20 03:07:25.190 24710 24710 F DEBUG : lr 0000007a770a9624 sp 0000007a6f7de9c0 pc 0000007a770a96a8 pst 0000000020000000
10-20 03:07:25.190 24710 24710 F DEBUG : backtrace:
10-20 03:07:25.190 24710 24710 F DEBUG : #00 pc 00000000000386a8 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/lib/arm64/liblanguage_id_l2c_jni.so (BuildId: be6e59455cc10135330c93acdebfc121)
10-20 03:07:25.190 24710 24710 F DEBUG : #01 pc 00000000000388a0 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/lib/arm64/liblanguage_id_l2c_jni.so (BuildId: be6e59455cc10135330c93acdebfc121)
10-20 03:07:25.190 24710 24710 F DEBUG : #02 pc 00000000000844a0 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/lib/arm64/liblanguage_id_l2c_jni.so (BuildId: be6e59455cc10135330c93acdebfc121)
10-20 03:07:25.190 24710 24710 F DEBUG : #03 pc 000000000008783c /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/lib/arm64/liblanguage_id_l2c_jni.so (BuildId: be6e59455cc10135330c93acdebfc121)
10-20 03:07:25.190 24710 24710 F DEBUG : #04 pc 0000000000035fc4 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/lib/arm64/liblanguage_id_l2c_jni.so (BuildId: be6e59455cc10135330c93acdebfc121)
10-20 03:07:25.190 24710 24710 F DEBUG : #05 pc 0000000000034954 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/lib/arm64/liblanguage_id_l2c_jni.so (BuildId: be6e59455cc10135330c93acdebfc121)
10-20 03:07:25.190 24710 24710 F DEBUG : #06 pc 00000000000340e8 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/lib/arm64/liblanguage_id_l2c_jni.so (Java_com_google_mlkit_nl_languageid_internal_ThickLanguageIdentifier_nativeIdentifyPossibleLanguages+108) (BuildId: be6e59455cc10135330c93acdebfc121)
10-20 03:07:25.191 24710 24710 F DEBUG : #07 pc 00000000002d9a44 /apex/com.android.art/lib64/libart.so (art_quick_generic_jni_trampoline+148) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #08 pc 000000000020a700 /apex/com.android.art/lib64/libart.so (nterp_helper+5648) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #09 pc 00000000000cd0dc /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #10 pc 000000000020a044 /apex/com.android.art/lib64/libart.so (nterp_helper+3924) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #11 pc 00000000000ccfa8 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #12 pc 0000000000557cb4 /system/framework/arm64/boot-framework.oat (android.os.Binder.transact+148) (BuildId: 43a571a0ad85d6451b47016336a541ecb0eb12bb)
10-20 03:07:25.191 24710 24710 F DEBUG : #13 pc 000000000020b53c /apex/com.android.art/lib64/libart.so (nterp_helper+9292) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #14 pc 00000000000b7aba /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #15 pc 000000000020a044 /apex/com.android.art/lib64/libart.so (nterp_helper+3924) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #16 pc 00000000000a7496 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #17 pc 000000000020a044 /apex/com.android.art/lib64/libart.so (nterp_helper+3924) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #18 pc 00000000000a7360 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #19 pc 000000000020ae64 /apex/com.android.art/lib64/libart.so (nterp_helper+7540) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #20 pc 000000000009e46c /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #21 pc 000000000020ae64 /apex/com.android.art/lib64/libart.so (nterp_helper+7540) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #22 pc 00000000000d33d6 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #23 pc 000000000020ae64 /apex/com.android.art/lib64/libart.so (nterp_helper+7540) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #24 pc 000000000009df0a /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #25 pc 0000000000209124 /apex/com.android.art/lib64/libart.so (nterp_helper+52) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #26 pc 000000000009e350 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #27 pc 000000000037b9ac /apex/com.android.art/javalib/arm64/boot.oat (java.util.concurrent.ThreadPoolExecutor.runWorker+988) (BuildId: ab2bf4ec264efdb6c452a238be38fe624de826b8)
10-20 03:07:25.191 24710 24710 F DEBUG : #28 pc 00000000003751d4 /apex/com.android.art/javalib/arm64/boot.oat (java.util.concurrent.ThreadPoolExecutor$Worker.run+68) (BuildId: ab2bf4ec264efdb6c452a238be38fe624de826b8)
10-20 03:07:25.191 24710 24710 F DEBUG : #29 pc 000000000020aec4 /apex/com.android.art/lib64/libart.so (nterp_helper+7636) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #30 pc 000000000009e370 /data/app/~~KjjULZV48O7KSOgOP1wYNQ==/com.example.myapplication-vFUidUPTjaGg4oo3SRAYJw==/oat/arm64/base.vdex
10-20 03:07:25.191 24710 24710 F DEBUG : #31 pc 00000000001bf35c /apex/com.android.art/javalib/arm64/boot.oat (java.lang.Thread.run+76) (BuildId: ab2bf4ec264efdb6c452a238be38fe624de826b8)
10-20 03:07:25.191 24710 24710 F DEBUG : #32 pc 00000000002d0164 /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+548) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #33 pc 000000000031ccac /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+156) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #34 pc 00000000003cf8a0 /apex/com.android.art/lib64/libart.so (art::JValue art::InvokeVirtualOrInterfaceWithJValues<art::ArtMethod*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, art::ArtMethod*, jvalue const*)+380) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #35 pc 0000000000460894 /apex/com.android.art/lib64/libart.so (art::Thread::CreateCallback(void*)+992) (BuildId: cdecb8dde1264c9871695c29854aa3b1)
10-20 03:07:25.191 24710 24710 F DEBUG : #36 pc 00000000000b1910 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+264) (BuildId: ba489d4985c0cf173209da67405662f9)
10-20 03:07:25.191 24710 24710 F DEBUG : #37 pc 00000000000513f0 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: ba489d4985c0cf173209da67405662f9)
ri...@gmail.com <ri...@gmail.com> #14
Cross-posted on R8 issue tracker.
ep...@gmail.com <ep...@gmail.com> #15
Hi,
Looks like we figured out the root cause in
For temporary workarounds for the existing SDKs, you need to add this rule
-keep class com.google.mlkit.nl.languageid.internal.LanguageIdentificationJni { *; }
for language-id 16.1.1
, and add this rule
-keep class com.google.mlkit.nl.languageid.internal.ThickLanguageIdentifier { *; }
for version language-id 17.0.0+
for the newer model.
We'll fix this issue in the upcoming release so that you'll not need these workarounds in the future release.
Thanks a lot for reporting this issue!
ra...@gmail.com <ra...@gmail.com> #16
Added workarounds in
xy...@gmail.com <xy...@gmail.com> #17
ho...@gmail.com <ho...@gmail.com> #18
br...@gmail.com <br...@gmail.com> #19
am...@gmail.com <am...@gmail.com> #20
to...@gmail.com <to...@gmail.com> #21
+1
lo...@gmail.com <lo...@gmail.com> #22
Hey folks, please stop adding +1 comments and use the dedicated star button at the top of the page instead.
That'll save some noise and avoid all the "stargazers" from getting unactionable emails.
Thank you.
ta...@mercury.com <ta...@mercury.com> #23
Here's a terrible, terrible hack to get the blur RenderEffect
for a Compose canvas.
The hack is terrible but it appears to work. You have been warned.
so...@gmail.com <so...@gmail.com> #24
de...@gmail.com <de...@gmail.com> #25
ya...@gmail.com <ya...@gmail.com> #26
ma...@gmail.com <ma...@gmail.com> #27
Hey folks, please stop adding +1 comments and use the dedicated star button at the top of the page instead.
That'll save some noise and avoid all the "stargazers" from getting unactionable emails.
Thank you.
[Deleted User] <[Deleted User]> #29
ap...@google.com <ap...@google.com> #31
Branch: androidx-main
commit 87b47565c30d75faf827b482a2dbad95c3016ca7
Author: Nader Jawad <njawad@google.com>
Date: Tue Aug 17 19:56:23 2021
Introduce BlurredEdgeTreatment API
Relnote: "Added BlurredEdgeTreatment API
to simplify blur use cases into more
commonly used combinations of clip flags
and TileModes. Most use cases involve
either letting blurred content render
outside the original content bounds
and blurring regions outside these bounds
with transparent black, or clipping content
to content bounds sampling the closest edge
for blur kernels that extend beyond content
bounds."
Bug: 166927547
Test: Added BlurTest
Change-Id: I6b4b7966920855374275ae7ea950b310fa28efd0
M compose/ui/ui/api/current.txt
M compose/ui/ui/api/public_plus_experimental_current.txt
M compose/ui/ui/api/restricted_current.txt
M compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/BlurSample.kt
A compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/BlurTest.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/draw/Blur.kt
ap...@google.com <ap...@google.com> #32
Branch: androidx-main
commit a04a6e81fdeba710a3790d30e113d203dd3ff390
Author: Nader Jawad <njawad@google.com>
Date: Tue Aug 03 17:37:24 2021
More RenderEffect support
Relnote: "Added support for RenderEffect
in compose desktop.
Introduced OffsetEffect as well as
the blur modifier as a simple way to
introduce blur visual effects to a portion
of the composition hierarchy."
Fixed order of operations issue on compose
desktop that prevented clipping from working
properly with saveLayer.
Bug: 166927547
Test: Added tests to RenderEffectTest/GraphicsLayerTest/
AndroidRenderEffectTest
Change-Id: I0f6aa293db2bf34f5ed2aa7499a97332dacf73fc
M compose/ui/ui-graphics/api/current.txt
M compose/ui/ui-graphics/api/public_plus_experimental_current.txt
M compose/ui/ui-graphics/api/restricted_current.txt
M compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/AndroidRenderEffectTest.kt
M compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidRenderEffect.android.kt
M compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/RenderEffect.kt
M compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopTileMode.desktop.kt
A compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/RenderEffect.desktop.kt
M compose/ui/ui-graphics/src/test/java/androidx/compose/ui/graphics/RenderEffectTest.kt
M compose/ui/ui/api/current.txt
M compose/ui/ui/api/public_plus_experimental_current.txt
M compose/ui/ui/api/restricted_current.txt
A compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/BlurSample.kt
A compose/ui/ui/samples/src/main/res/drawable/circus.jpg
M compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/GraphicsLayerModifierTest.kt
M compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/GraphicsLayerTest.kt
A compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/draw/Blur.kt
M compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/SkijaLayer.desktop.kt
M compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/platform/SkijaLayerTest.kt
ap...@google.com <ap...@google.com> #33
Branch: androidx-main
commit af8e89a54fb3173251a43251bd8a0bda2a126c66
Author: Nader Jawad <njawad@google.com>
Date: Fri Jul 30 18:46:49 2021
Add RenderEffect API
Relnote: "Introduced RenderEffect API
that can be optionally configured on
a Modifier.graphicsLayer to alter
the contents of the layer itself. This
can be used to blur contents of a composable
and child composables within a composition
hierarchy."
Bug: 166927547
Test: Added tests to RenderEffectTest/GraphicsLayerTest/
AndroidRenderEffectTest
Change-Id: I47c4d5ecc801f35e632d2062e03c756f564a2db5
M compose/ui/ui-graphics/api/current.txt
M compose/ui/ui-graphics/api/public_plus_experimental_current.txt
M compose/ui/ui-graphics/api/restricted_current.txt
A compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/AndroidRenderEffectTest.kt
A compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidRenderEffect.android.kt
A compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/RenderEffect.kt
A compose/ui/ui-graphics/src/test/java/androidx/compose/ui/graphics/RenderEffectTest.kt
M compose/ui/ui/api/current.ignore
M compose/ui/ui/api/current.txt
M compose/ui/ui/api/public_plus_experimental_current.txt
M compose/ui/ui/api/restricted_current.ignore
M compose/ui/ui/api/restricted_current.txt
M compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
M compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/GraphicsLayerTest.kt
M compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/DeviceRenderNode.android.kt
M compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeApi23.android.kt
M compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeApi29.android.kt
M compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/RenderNodeLayer.android.kt
M compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ViewLayer.android.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/GraphicsLayerModifier.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/GraphicsLayerScope.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeWrapper.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OwnedLayer.kt
M compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/SkijaLayer.desktop.kt
M compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
ap...@google.com <ap...@google.com> #34
Branch: androidx-main
commit 1d626519ace91a88f1a08d02b24d3741dea10b95
Author: Nader Jawad <njawad@google.com>
Date: Thu Jul 29 15:23:06 2021
Introduce TileMode.Decal
Relnote: "Add TileMode.Decal support
which is useful in defining edge
behavior for blur based RenderEffects."
Bug: 166927547
Test: Added tests to TileModeTest and
AndroidTileModeTest
Change-Id: I7e8ed0c4eb2490ef3cd0032b5952d0962f489354
M compose/ui/ui-graphics/api/current.txt
M compose/ui/ui-graphics/api/public_plus_experimental_current.txt
M compose/ui/ui-graphics/api/restricted_current.txt
A compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/AndroidTileModeTest.kt
M compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidTileMode.android.kt
M compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/TileMode.kt
M compose/ui/ui-graphics/src/test/java/androidx/compose/ui/graphics/TileModeTest.kt
el...@gmail.com <el...@gmail.com> #35
nj...@google.com <nj...@google.com>
cs...@google.com <cs...@google.com> #36
🎉🎉🎉
fa...@gmail.com <fa...@gmail.com> #37
when will it be ready for use? And short guideline would great. Thank you for the fast reaction!
da...@gmail.com <da...@gmail.com> #38
Nice, which version of compose will have this?
Is it android 12 only or backported? Thanks and well done!
nj...@google.com <nj...@google.com> #39
This API is supported on Android 12 only and is a no-op for older API levels.
Blur is supported as a Modifier API and common usage would look like the following:
Box(modifier = Modifier.size(100.dp).blur(30.dp)) {
// child composable
}
[Deleted User] <[Deleted User]> #40
se...@gmail.com <se...@gmail.com> #41
It's already been released with Compose 1.1.0-alpha03
ru...@gmail.com <ru...@gmail.com> #42
sh...@gmail.com <sh...@gmail.com> #43
is it supported in android < 12
si...@gmail.com <si...@gmail.com> #44
ri...@gmail.com <ri...@gmail.com> #45
I think this question should be reopened? It doesn't support versions below Android S, as a non-system ui framework, this is very disappointing.
ja...@gmail.com <ja...@gmail.com> #46
And Kotlin Multiplatform info should be great too
sh...@gmail.com <sh...@gmail.com> #47
The Blur Modifier in compose currently only supports the API 31, hence it is of no use. I tried to create a blur Modifier by first drawing the content on the bitmap canvus and the blur it and draw it on target canvus. but it seems compose does expose the draw(canvus) like in ViewWorld. Currently I looked the docs of Test ScreenShot, Magnifier but both of these use onGloballyPositioned to capture the piece of bitmap from LocalView. Hence it doesn't do what I intended it to do.
There is another solution that involves Creating a Blury View and then use composed to make a modifier (But I don't like this solution.). If anybody knows how to achieve it please do tell me.
mg...@gmail.com <mg...@gmail.com> #48
bl...@gmail.com <bl...@gmail.com> #49
cs...@google.com <cs...@google.com> #50
To
On the "glassmorphism" effect, could send a link to exactly what effect do you mean?
ga...@gmail.com <ga...@gmail.com> #51
+1
wo...@gmail.com <wo...@gmail.com> #52
mg...@gmail.com <mg...@gmail.com> #53
The best I can show you without putting to much effort on it, it is some images examples:
Here, the card receives an alpha color and the elements located behind it receive a level o blur.
As you move the front element, the back ones dynamically interact with it.
And the effect, as you can see, can be stacked.
ca...@usp.br <ca...@usp.br> #54
Glassmorphism would be great since it opens several UI possibilities (that right now seems only feasible for iOS). In Brazil, Android is predominant and there's a current trend among UXs to adopt glassmorphic like effects. The only thing holding us back is the implementation friction.
Plenty use cases here:
ra...@gmail.com <ra...@gmail.com> #55
We need it
cs...@google.com <cs...@google.com> #56
Regarding
mg...@gmail.com <mg...@gmail.com> #57
mg...@gmail.com <mg...@gmail.com> #58
Searching through the internet, you can find quite a lot of examples on how to implement background blur. All the examples, although different in execution, uses the same logic:
1 - You choose a root for you effect;
2 - You choose the view you want to apply the effect on;
3 - You observe the view relative position into the view tree;
4 - When the view is showing itself on the screen, fully or partially, you start the following computation:
a - Get the matrix dimension of the desired view;
b - Generates a bitmap from the dimensions of the view;
c - Scale down to a proper scale so the next steps don't consume too much resources;
d - With the scaled bitmap, apply algorithms of image treatment to achieve the blur effect;
e - With the blurred bitmap, paint it on a canvas based on the dimensions of the view;
f - finally, display the blurred view on the place of a normal view (with transparent on it).
As you can see, this process is kind of a cheat one. It can work well in some cases, but most of them are just terrible. The more your components move in screen, the harder it becomes to achieve performance and better looking effects.
Another downside of this method is its compatibility with the composable way of working. On old style android, each fragment / activity is its own view. But, that's not the case for compose: the whole thing is a single view. There are some ways of transforming Compose component -> Compose View -> Android View, creating some sort of old android view tree, but that's just nasty and prune to bad results.
After experimenting with all of these, I was looking into the Composable Canvas, having a lot fun with it by the way, and I realized the presence of a very interesting effect which can be applied to the drawing: blend mode.
Blend mode has some interesting visual effects on the drawing. It computes a mix of RGB channels so the back composable interacts with the children component mixing the visuals. It's almost the same principle used in the background blur, but instead of pixels effect, it's a color effect. The blend mode, funny enough, just breaks with the new Blur Effect from composable.
Finally, a last but interesting discover, is the
mg...@gmail.com <mg...@gmail.com> #60
[Deleted User] <[Deleted User]> #61
ba...@gmail.com <ba...@gmail.com> #62
Dear Android Team,
Current design i.e Modifier.blur(50.dp)
supports blur on the composable itself not underneath. But its use is too much limited. What most of the people here and elsewhere are
looking for overlay blur which is not supported.
I don't think it is a too hard to even comprehend kind of request. If you guys believe it is. Kindly give us a response of why it is that hard to implemented a overlay blur.
da...@gmail.com <da...@gmail.com> #63
Android 12 introduced support for RenderEffect
s including blurring, even though out-of-the-box it would blur the View
itself, and not any content underneath it — so it's not a backdrop blur (in CSS terms, it's like filter: blur()
and not backdrop-filter: blur()
).
However, internally, Views are backed by RenderNode
s, which ultimately apply RenderEffects. By leveraging RenderNodes, it's possible to implement backdrop blurring, and I've done that with Compose. Note that it's for Android 12 onwards.
For anyone interested, the implementation is at the end of the post.
Sample usage
It works in a producer–consumer manner, where the producer is any composable with Modifier.backdropContent
(which feeds the composable into the Backdrop
) and the consumer is any composable with Modifier.backdrop
(which takes content from the specified Backdrop
and draws it behind the composable, applying a RenderEffect
to it). The Backdrop
class thus serves to connect the producers and the consumers and it also stores the content being produced — the backdrop. You obtain an instance of Backdrop
using the rememberBackdrop
function.
To further simplify usage on the consumer part, I also implemented Modifier.blurredSurface
, which accepts a surfaceColor
, blurRadius
, saturation
, and a border stroke
, and sets up the backdrop with the appropriate RenderEffect
automatically. The following example should show a list (to be populated) and a blurred bar overlaid on top of the list.
- Note: I haven't tested the example, but the implementation works in my app.
@Composable
fun BackdropBlurDemo() {
val backdrop = rememberBackdrop()
val listState = rememberLazyListState()
val showDivider = listState.canScrollForward
Box(modifier = Modifier.fillMaxSize()) {
Box(
modifier = Modifier
.fillMaxWidth()
.requiredHeight(56.dp)
.blurredSurface(backdrop) {
BlurredSurfaceDefaults.parameters(
strokeAlpha = when {
showDivider -> BlurredSurfaceDefaults.DefaultStrokeAlpha
else -> 0f
},
strokeAlphaAnimationSpec = spring()
)
}
)
LazyColumn(
state = listState,
modifier = Modifier
.matchParentSize()
.backdropContent(backdrop)
) {
// Load some items
}
}
}
Implementation
Notes:
- Some
import
s may be missing or unordered, I joined several files to post the code here. - The implementation depends on the artifact
androidx.compose.ui:ui-util
.
import android.graphics.RenderNode
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.material3.DividerDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.*
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.layout.*
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.util.packFloats
import androidx.compose.ui.util.unpackFloat1
import androidx.compose.ui.util.unpackFloat2
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
import kotlin.math.roundToInt
import kotlin.reflect.KProperty
@Immutable
data class BlurredSurfaceParameters(
val surfaceColor: Color,
val blurRadius: Dp,
val saturation: Float,
val stroke: DpStroke?
) {
@JvmField
internal val paint = Paint().also { paint ->
paint.colorFilter = ColorFilter.colorMatrix(
colorMatrix = when (val saturation = saturation) {
1f -> {
MakeOpaqueColorMatrix
}
else -> ColorMatrix().also { colorMatrix ->
colorMatrix.setToSaturation(saturation)
colorMatrix *= MakeOpaqueColorMatrix
}
}
)
}
}
@Immutable
object BlurredSurfaceDefaults {
const val DefaultSurfaceOpacity = 0.5f
@JvmStatic val DefaultBlurRadius = 24.dp
const val DefaultSaturation = 1.3f
const val DefaultStrokeAlpha = 0.7f
@Composable
fun parameters(
surfaceColor: Color = MaterialTheme.colorScheme.surface,
surfaceOpacity: Float = DefaultSurfaceOpacity,
blurRadius: Dp = DefaultBlurRadius,
saturation: Float = DefaultSaturation,
strokeAlpha: Float = DefaultStrokeAlpha,
strokeAlphaAnimationSpec: AnimationSpec<Float>? = null,
stroke: DpStroke? = DpStroke(
width = DividerDefaults.Thickness,
color = MaterialTheme.colorScheme.outlineVariant,
parameters = StrokeParameters(
alignment = -1f,
alpha = when (strokeAlphaAnimationSpec) {
null -> strokeAlpha
else -> animateFloatAsState(
targetValue = strokeAlpha,
animationSpec = strokeAlphaAnimationSpec,
visibilityThreshold = 1f / 255f,
label = "blurredSurface strokeAlpha"
).value
},
blendMode = BlendMode.Luminosity
)
)
) = BlurredSurfaceParameters(
surfaceColor = surfaceColor.copy(alpha = surfaceOpacity),
blurRadius = blurRadius,
saturation = saturation,
stroke = stroke
)
}
fun Modifier.blurredSurface(
backdrop: Backdrop,
parameters: @DisallowComposableCalls @Composable () -> BlurredSurfaceParameters = {
BlurredSurfaceDefaults.parameters()
}
) = composed {
val currentParameters by rememberUpdatedState(parameters())
val currentDensity by rememberUpdatedState(LocalDensity.current)
val background: DrawScope.() -> Unit = remember {
{ drawRect(currentParameters.surfaceColor.copy(alpha = 1f)) }
}
remember {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
backdrop(
backdrop = backdrop,
background = background,
paint = { currentParameters.paint },
renderEffect = {
with(currentDensity) {
val radiusPx = currentParameters.blurRadius.toPx()
BlurEffect(
radiusX = radiusPx,
radiusY = radiusPx,
edgeTreatment = TileMode.Decal
)
}
}
).drawBehind {
drawRect(currentParameters.surfaceColor)
}
} else {
drawBehind(background)
}
}
.stroke(currentParameters.stroke)
}
private val MakeOpaqueColorMatrix = ColorMatrix(
floatArrayOf(
1f, 0f, 0f, 0f, 0f,
0f, 1f, 0f, 0f, 0f,
0f, 0f, 1f, 0f, 0f,
0f, 0f, 0f, 0f, 255f
)
)
@Composable
fun rememberBackdrop(): Backdrop =
remember { Backdrop() }
@RequiresApi(Build.VERSION_CODES.S)
fun Modifier.backdropContent(
backdrop: Backdrop,
paint: () -> Paint? = Backdrop.DefaultPrePaint
): Modifier {
val paintState = derivedStateOf(structuralEqualityPolicy(), paint)
return composed {
remember(backdrop) {
backdrop.ContentNode(paintState = paintState)
}.modifier
}
}
@RequiresApi(Build.VERSION_CODES.S)
fun Modifier.backdrop(
backdrop: Backdrop,
inset: Dp = 0.dp,
background: (DrawScope.() -> Unit)? = null,
paint: () -> Paint? = Backdrop.DefaultPostPaint,
renderEffect: () -> RenderEffect
): Modifier {
val paintState = derivedStateOf(structuralEqualityPolicy(), paint)
val renderEffectState = derivedStateOf(structuralEqualityPolicy(), renderEffect)
return composed {
remember(backdrop) {
BackdropNode(
backdrop = backdrop,
paintState = paintState,
renderEffectState = renderEffectState,
initialInsetDp = inset.value
)
}
.also { it.background = background }
.also { it.insetDp = inset.value }
.modifier
}
}
class Backdrop internal constructor() {
@Immutable
internal companion object {
@JvmStatic internal val DefaultPrePaint: () -> Paint? = { null }
@JvmStatic internal val DefaultPostPaint: () -> Paint? = { null }
@JvmStatic private val DefaultPrePaintValue = NativePaint()
}
private var contentNodeHead: ContentNode? = null
private var contentNodeTail: ContentNode? = null
@OptIn(ExperimentalContracts::class)
internal inline fun forEachNode(
block: (ContentNode) -> Unit
) {
contract {
callsInPlace(block)
}
contentNodeHead?.forEach(block)
}
internal inner class ContentNode
/**
* Creates a [ContentNode] that is added to this [Backdrop] when remembered
* and removed when forgotten.
*
* Always create inside a [remember] block.
*/
@RequiresApi(Build.VERSION_CODES.Q)
constructor(
paintState: State<Paint?>
) :
RememberObserver {
@RequiresApi(Build.VERSION_CODES.Q)
override fun onRemembered() {
append()
}
override fun onForgotten() {
remove()
}
override fun onAbandoned() {
remove()
}
var renderNode: RenderNode? = null
private set
val paint by paintState
var position by mutableOffsetStateDelegateOf(Offset.Zero)
private set
/**
* The [Modifier] to be used in [backdropContent].
*/
@RequiresApi(Build.VERSION_CODES.Q)
@JvmField
val modifier = Modifier
.onPlaced { position = it.positionInRoot() }
.drawWithContent {
renderNode?.let { renderNode ->
renderNode.setUseCompositingLayer(
true,
paint?.asFrameworkPaint() ?: DefaultPrePaintValue
)
val (width, height) = size.round()
renderNode.setPosition(0, 0, width, height)
withNode(renderNode) { drawContent() }
}
}
private var previous: ContentNode? = null
private var next: ContentNode? = null
@OptIn(ExperimentalContracts::class)
inline fun forEach(
block: (ContentNode) -> Unit
) {
contract {
callsInPlace(block)
}
var node = this
while (true) {
block(node)
node = node.next ?: break
}
}
@RequiresApi(Build.VERSION_CODES.Q)
private fun append() {
if (renderNode != null)
return
renderNode = RenderNode("content")
this@Backdrop.contentNodeTail = apply {
when (val tail = this@Backdrop.contentNodeTail) {
null -> {
contentNodeHead = this
}
else -> {
tail.next = this
this.previous = tail
}
}
}
}
private fun remove() {
if (renderNode == null)
return
renderNode = null
val previous = this.previous
val next = this.next
previous?.next = next
next?.previous = previous
if (this@Backdrop.contentNodeHead === this)
this@Backdrop.contentNodeHead = next
if (this@Backdrop.contentNodeTail === this)
this@Backdrop.contentNodeTail = previous
}
}
}
@RequiresApi(Build.VERSION_CODES.S)
private class BackdropNode(
private val backdrop: Backdrop,
paintState: State<Paint?>,
renderEffectState: State<RenderEffect>,
initialBackground: (DrawScope.() -> Unit)? = null,
initialInsetDp: Float
) {
private var position by mutableOffsetStateDelegateOf(Offset.Zero)
private val backdropNode = RenderNode("backdrop")
val renderEffect by renderEffectState
val paint by paintState
var background by mutableStateOf(initialBackground)
var insetDp by mutableFloatStateOf(initialInsetDp)
/**
* The [Modifier] to be used in [backdrop].
*/
@JvmField
val modifier = Modifier
.onPlaced { position = it.positionInRoot() }
.drawBehind {
val backdropNode = backdropNode
val (width, height) = size.round()
val inset = insetDp.dp.roundToPx()
backdropNode.setRenderEffect(renderEffect.asAndroidRenderEffect())
backdropNode.setPosition(
inset,
inset,
width - inset,
height - inset
)
backdropNode.withRecording { blurCanvas ->
backdrop.forEachNode { contentNode ->
contentNode.renderNode?.let { renderNode ->
val (sx, sy) = contentNode.position
val (dx, dy) = this@BackdropNode.position
val tx = sx - dx - inset
val ty = sy - dy - inset
blurCanvas.translate(+tx, +ty)
blurCanvas.drawRenderNode(renderNode)
blurCanvas.translate(-tx, -ty)
}
}
}
with(drawContext.canvas.androidCanvas) {
val saveCount = saveLayer(
0f,
0f,
width.toFloat(),
height.toFloat(),
paint?.asFrameworkPaint()
)
background?.invoke(this@drawBehind)
drawRenderNode(backdropNode)
restoreToCount(saveCount)
}
}
}
@Stable
private inline fun Size.round(): IntSize =
IntSize(
width = width.roundToInt(),
height = height.roundToInt()
)
@OptIn(ExperimentalContracts::class)
@RequiresApi(Build.VERSION_CODES.Q)
private inline fun <R> RenderNode.withRecording(
block: (Canvas) -> R
): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return try {
block(beginRecording())
} finally {
endRecording()
}
}
@OptIn(ExperimentalContracts::class)
@RequiresApi(Build.VERSION_CODES.Q)
private inline fun <T : DrawScope, R> T.withNode(
renderNode: RenderNode,
draw: T.() -> R
): R {
contract {
callsInPlace(draw, InvocationKind.EXACTLY_ONCE)
}
val composeCanvas = drawContext.canvas
val nativeCanvas = composeCanvas.androidCanvas
val result: R
renderNode.withRecording { rnCanvas ->
composeCanvas.androidCanvas = rnCanvas
result = draw()
composeCanvas.androidCanvas = nativeCanvas
}
nativeCanvas.drawRenderNode(renderNode)
return result
}
private fun mutableOffsetStateDelegateOf(value: Offset) = OffsetStateDelegate(value = value)
@JvmInline
private value class OffsetStateDelegate private constructor(
private val state: MutableLongState
) {
constructor(value: Offset) : this(
state = mutableLongStateOf(value.toLongValue())
)
operator fun getValue(thisObj: Any?, property: KProperty<*>): Offset =
state.longValue.let { boundsValue ->
Offset(
x = unpackFloat1(boundsValue),
y = unpackFloat2(boundsValue)
)
}
operator fun setValue(
thisObj: Any?,
property: KProperty<*>,
value: Offset
) {
state.longValue = value.toLongValue()
}
@Immutable
private companion object {
@Suppress("NOTHING_TO_INLINE")
@Stable
private inline fun Offset.toLongValue() = packFloats(x, y)
}
}
License: No specific license, I'm offering this for any kind of use or modification.
sh...@gmail.com <sh...@gmail.com> #64
Hi, I’m the author of the Toolkit library, which contains a custom blur modifier that can blur the background behind any composable in real time. It works on any version of Android.
I wrote an article that shows how to use my library and how to create stunning glassmorphic designs for your Android apps. You can read it here: Blurring the Lines: How to Achieve a Glassmorphic Design with Jetpack Compose.
link:
I hope you find my library and article helpful. If you have any feedback or suggestions, please let me know.
Description
It was mentioned in a Dev YouTube video that Compose will be design system agnostic. In order to achieve that, it would make sense to natively support blurring as some design systems use it. Also, there are designers that don't necessary use MD while designing apps for Android,
and in that case if they use blur usually they either have to find an alternative
or the devs have a really hard time getting it to work consistently across all devices.
Ideally, blurring would be supported on all container layouts such as CardView, ConstraintLayout etc. (all that inherit from ViewGroup?). The API should be something like this:
Modifier.blur(radius = 16.dp, dynamic = true)
Dynamic = true/false would mean either realtime blurring in moving/scrolling layouts or one-time-blur on static content to minimize performance impact when dynamic blurring is not needed.
As for the current problems of blurring in Android - the only way to implement it is using RenderScript or an external library (from which most rely on RenderScript anyway).
When using it the API is usually complicated and after some testing on different devices it seems
as the performance impact depends on the chipset where Snapdragon devices have no perceivable lag and for ex. Kirin and Exynos devices drop frames to a point where it is not feasable to keep blur in UI.