diff --git a/examples/agdk-mainloop/.gitignore b/examples/agdk-mainloop/.gitignore index 9f8412da..810307fe 100644 --- a/examples/agdk-mainloop/.gitignore +++ b/examples/agdk-mainloop/.gitignore @@ -1,8 +1,8 @@ *.iml -.idea .gradle /local.properties /.idea +/.vscode .DS_Store /build /captures diff --git a/examples/agdk-mainloop/Cargo.lock b/examples/agdk-mainloop/Cargo.lock new file mode 100644 index 00000000..9bd2d240 --- /dev/null +++ b/examples/agdk-mainloop/Cargo.lock @@ -0,0 +1,679 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "agdk-mainloop" +version = "0.1.0" +dependencies = [ + "android-activity", + "jni", + "paranoid-android", + "tracing", + "tracing-log", + "tracing-subscriber", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-activity" +version = "0.6.0" +dependencies = [ + "android-properties", + "bitflags", + "cc", + "jni", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys 0.6.0+11769913", + "num_enum", + "simd_cesu8", + "thiserror 2.0.18", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cc" +version = "1.2.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom", + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags", + "jni-sys 0.3.0", + "log", + "ndk-sys 0.6.0+11769913", + "num_enum", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys 0.3.0", +] + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys 0.3.0", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "paranoid-android" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "101795d63d371b43e38d6e7254677657be82f17022f7f7893c268f33ac0caadc" +dependencies = [ + "lazy_static", + "ndk-sys 0.5.0+25.2.9519653", + "sharded-slab", + "smallvec", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd_cesu8" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "toml_datetime" +version = "1.0.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.4+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.9+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +dependencies = [ + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" diff --git a/examples/agdk-mainloop/Cargo.toml b/examples/agdk-mainloop/Cargo.toml index ebf11973..166a2188 100644 --- a/examples/agdk-mainloop/Cargo.toml +++ b/examples/agdk-mainloop/Cargo.toml @@ -6,12 +6,20 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -log = "0.4" -android_logger = "0.11.0" -android-activity = { path="../../android-activity", features = ["game-activity"] } -ndk-sys = "0.6.0" -ndk = "0.9.0" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = [ + "fmt", + "env-filter", + "tracing-log", +] } +paranoid-android = "0.2" +tracing-log = "0.2" + +android-activity = { path = "../../android-activity", features = [ + "game-activity", +] } +jni = "0.22" [lib] -name="main" -crate_type=["cdylib"] +name = "main" +crate-type = ["cdylib"] diff --git a/examples/agdk-mainloop/README.md b/examples/agdk-mainloop/README.md index bdedbbfc..19a6abb3 100644 --- a/examples/agdk-mainloop/README.md +++ b/examples/agdk-mainloop/README.md @@ -13,5 +13,5 @@ cargo install cargo-ndk cargo ndk -t arm64-v8a -o app/src/main/jniLibs/ build ./gradlew build ./gradlew installDebug -adb shell am start -n co.realfit.agdkmainloop/.MainActivity +adb shell am start -n com.github.rust_mobile.agdkmainloop/.MainActivity ``` diff --git a/examples/agdk-mainloop/app/build.gradle b/examples/agdk-mainloop/app/build.gradle index 05368ce7..3a2ce53b 100644 --- a/examples/agdk-mainloop/app/build.gradle +++ b/examples/agdk-mainloop/app/build.gradle @@ -3,20 +3,19 @@ plugins { } android { - ndkVersion "25.2.9519653" - compileSdk 31 + compileSdk = 35 defaultConfig { - applicationId "co.realfit.agdkmainloop" - minSdk 28 - targetSdk 31 - versionCode 1 - versionName "1.0" + applicationId = "com.github.rust_mobile.agdkmainloop" + minSdk = 31 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" } buildTypes { release { - minifyEnabled false + minifyEnabled = false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } debug { @@ -28,32 +27,17 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } - namespace 'co.realfit.agdkmainloop' + namespace = 'com.github.rust_mobile.agdkmainloop' } dependencies { - - implementation "androidx.core:core:1.5.0" - implementation "androidx.constraintlayout:constraintlayout:2.0.4" - implementation 'androidx.fragment:fragment:1.2.5' - implementation 'com.google.oboe:oboe:1.5.0' - - // To use the Android Frame Pacing library - //implementation "androidx.games:games-frame-pacing:1.9.1" - - // To use the Android Performance Tuner - //implementation "androidx.games:games-performance-tuner:1.5.0" + implementation 'androidx.appcompat:appcompat:1.7.0' // To use the Games Activity library - implementation "androidx.games:games-activity:4.0.0" - - // To use the Games Controller Library - //implementation "androidx.games:games-controller:2.0.2" - - // To use the Games Text Input Library - //implementation "androidx.games:games-text-input:2.0.2" + implementation "androidx.games:games-activity:4.4.0" + // Note: don't include game-text-input separately, since it's integrated into game-activity } diff --git a/examples/agdk-mainloop/app/src/main/AndroidManifest.xml b/examples/agdk-mainloop/app/src/main/AndroidManifest.xml index b9d7563b..6a400f97 100644 --- a/examples/agdk-mainloop/app/src/main/AndroidManifest.xml +++ b/examples/agdk-mainloop/app/src/main/AndroidManifest.xml @@ -2,12 +2,11 @@ + android:theme="@style/ActivityTheme"> = VERSION_CODES.P) { - getWindow().getAttributes().layoutInDisplayCutoutMode - = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; - } + getWindow().getAttributes().layoutInDisplayCutoutMode + = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; // From API 30 onwards, this is the recommended way to hide the system UI, rather than // using View.setSystemUiVisibility. View decorView = getWindow().getDecorView(); diff --git a/examples/agdk-mainloop/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/examples/agdk-mainloop/app/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 2b068d11..00000000 --- a/examples/agdk-mainloop/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/examples/agdk-mainloop/app/src/main/res/drawable/ic_launcher_background.xml b/examples/agdk-mainloop/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9c..00000000 --- a/examples/agdk-mainloop/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/examples/agdk-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index eca70cfe..036d09bc 100644 --- a/examples/agdk-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/examples/agdk-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/examples/agdk-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index eca70cfe..036d09bc 100644 --- a/examples/agdk-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/examples/agdk-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/examples/agdk-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher.webp index c209e78e..f08a4124 100644 Binary files a/examples/agdk-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher.webp and b/examples/agdk-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/examples/agdk-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..a7af7759 Binary files /dev/null and b/examples/agdk-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/examples/agdk-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp index b2dfe3d1..0b9af008 100644 Binary files a/examples/agdk-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and b/examples/agdk-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/examples/agdk-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher.webp index 4f0f1d64..0f38950f 100644 Binary files a/examples/agdk-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher.webp and b/examples/agdk-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/examples/agdk-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..e4bdf4e3 Binary files /dev/null and b/examples/agdk-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/examples/agdk-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp index 62b611da..9e3cf92d 100644 Binary files a/examples/agdk-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and b/examples/agdk-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/examples/agdk-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher.webp index 948a3070..8d975559 100644 Binary files a/examples/agdk-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and b/examples/agdk-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/examples/agdk-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..7a7a6a4d Binary files /dev/null and b/examples/agdk-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/examples/agdk-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp index 1b9a6956..d8424d37 100644 Binary files a/examples/agdk-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and b/examples/agdk-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/examples/agdk-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp index 28d4b77f..61526f2a 100644 Binary files a/examples/agdk-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and b/examples/agdk-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/examples/agdk-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..90692d1a Binary files /dev/null and b/examples/agdk-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/examples/agdk-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp index 9287f508..717f69d4 100644 Binary files a/examples/agdk-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and b/examples/agdk-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/examples/agdk-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp index aa7d6427..1349310f 100644 Binary files a/examples/agdk-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and b/examples/agdk-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/examples/agdk-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..c055957d Binary files /dev/null and b/examples/agdk-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ diff --git a/examples/agdk-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/examples/agdk-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp index 9126ae37..91c850d2 100644 Binary files a/examples/agdk-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and b/examples/agdk-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/examples/agdk-mainloop/app/src/main/res/values/ic_launcher_background.xml b/examples/agdk-mainloop/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 00000000..ece04f86 --- /dev/null +++ b/examples/agdk-mainloop/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #C8C49F + \ No newline at end of file diff --git a/examples/agdk-mainloop/app/src/main/res/values/themes.xml b/examples/agdk-mainloop/app/src/main/res/values/themes.xml index 96e02419..1ac56313 100644 --- a/examples/agdk-mainloop/app/src/main/res/values/themes.xml +++ b/examples/agdk-mainloop/app/src/main/res/values/themes.xml @@ -1,3 +1,8 @@ - - \ No newline at end of file diff --git a/examples/agdk-mainloop/build.gradle b/examples/agdk-mainloop/build.gradle index 8ba8ae99..13dbbc60 100644 --- a/examples/agdk-mainloop/build.gradle +++ b/examples/agdk-mainloop/build.gradle @@ -1,10 +1,6 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '8.0.0' apply false - id 'com.android.library' version '8.0.0' apply false -} - -task clean(type: Delete) { - delete rootProject.buildDir + id 'com.android.application' version '9.1.0' apply false + id 'com.android.library' version '9.1.0' apply false } diff --git a/examples/agdk-mainloop/gradle.properties b/examples/agdk-mainloop/gradle.properties index ec63151a..a400a79b 100644 --- a/examples/agdk-mainloop/gradle.properties +++ b/examples/agdk-mainloop/gradle.properties @@ -1,23 +1,15 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app"s APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn +# Enable Gradle Daemon +org.gradle.daemon=true + +# JVM arguments +org.gradle.jvmargs=-Xmx4g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +# Enable AndroidX android.useAndroidX=true -# Enables namespacing of each library's R class so that its R class includes only the -# resources declared in the library itself and none from the library's dependencies, -# thereby reducing the size of the R class for that library -android.nonTransitiveRClass=true -android.defaults.buildfeatures.buildconfig=true -android.nonFinalResIds=false \ No newline at end of file +# Build caching and parallel execution +org.gradle.caching=true +org.gradle.parallel=true +# Incremental Kotlin compilation +kotlin.incremental=true + +# File system watching for faster builds +org.gradle.unsafe.watch-fs=true \ No newline at end of file diff --git a/examples/agdk-mainloop/gradle/wrapper/gradle-wrapper.jar b/examples/agdk-mainloop/gradle/wrapper/gradle-wrapper.jar index e708b1c0..a4b76b95 100644 Binary files a/examples/agdk-mainloop/gradle/wrapper/gradle-wrapper.jar and b/examples/agdk-mainloop/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/agdk-mainloop/gradle/wrapper/gradle-wrapper.properties b/examples/agdk-mainloop/gradle/wrapper/gradle-wrapper.properties index c3349a37..37f78a6a 100644 --- a/examples/agdk-mainloop/gradle/wrapper/gradle-wrapper.properties +++ b/examples/agdk-mainloop/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ -#Mon May 02 15:39:12 BST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip distributionPath=wrapper/dists -zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/agdk-mainloop/gradlew b/examples/agdk-mainloop/gradlew index 4f906e0c..f5feea6d 100644 --- a/examples/agdk-mainloop/gradlew +++ b/examples/agdk-mainloop/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,69 +15,104 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +122,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,88 +133,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/examples/agdk-mainloop/gradlew.bat b/examples/agdk-mainloop/gradlew.bat index 107acd32..9b42019c 100644 --- a/examples/agdk-mainloop/gradlew.bat +++ b/examples/agdk-mainloop/gradlew.bat @@ -1,89 +1,94 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/agdk-mainloop/src/lib.rs b/examples/agdk-mainloop/src/lib.rs index a2f94e7f..25ad97ea 100644 --- a/examples/agdk-mainloop/src/lib.rs +++ b/examples/agdk-mainloop/src/lib.rs @@ -1,12 +1,142 @@ +use std::sync::OnceLock; + use android_activity::{ input::{InputEvent, KeyAction, KeyEvent, KeyMapChar, MotionAction}, - AndroidApp, InputStatus, MainEvent, PollEvent, + ndk, ndk_sys, AndroidApp, InputStatus, MainEvent, OnCreateState, PollEvent, +}; +use jni::{ + objects::{JObject, JString}, + refs::Global, + vm::JavaVM, }; -use log::info; +use tracing::{error, info}; + +jni::bind_java_type! { Context => "android.content.Context" } +jni::bind_java_type! { + Activity => "android.app.Activity", + type_map { + Context => "android.content.Context", + }, + is_instance_of { + context: Context + }, +} + +jni::bind_java_type! { + Toast => "android.widget.Toast", + type_map { + Context => "android.content.Context", + }, + methods { + static fn make_text(context: Context, text: JCharSequence, duration: i32) -> Toast, + fn show(), + } +} + +// Note: The jni bindings will actually initialize lazily but it can be helpful +// to initialize explicitly to get an up-front error in case there is an issue +// (such as a typo with a method name or incorrect signature) rather than having +// an unpredictable error when using the binding. +fn jni_init(env: &jni::Env) -> jni::errors::Result<()> { + let _ = ContextAPI::get(env, &Default::default())?; + let _ = ActivityAPI::get(env, &Default::default())?; + let _ = ToastAPI::get(env, &Default::default())?; + // .. call other `get` functions for other bindings here as needed ... + Ok(()) +} + +// Called while Activity.onCreate is running +// May be called multiple times if the activity is destroyed and recreated. +#[unsafe(no_mangle)] +fn android_on_create(state: &OnCreateState) { + static ONCE: OnceLock<()> = OnceLock::new(); + ONCE.get_or_init(|| { + use tracing_subscriber::prelude::*; + + unsafe { std::env::set_var("RUST_BACKTRACE", "full") }; + + const DEFAULT_ENV_FILTER: &str = "debug,wgpu_hal=info,winit=info,naga=info"; + let filter_layer = tracing_subscriber::EnvFilter::new(DEFAULT_ENV_FILTER); + let android_layer = paranoid_android::layer(env!("CARGO_PKG_NAME")) + .with_ansi(false) + .with_span_events(tracing_subscriber::fmt::format::FmtSpan::CLOSE) + .with_thread_names(true); + tracing_subscriber::registry() + .with(filter_layer) + .with(android_layer) + .init(); + }); + + let vm = unsafe { JavaVM::from_raw(state.vm_as_ptr().cast()) }; + // Note: from here on we can also rely on `JavaVM::singleton()` now that we know it's been initialized. + + let activity = state.activity_as_ptr() as jni::sys::jobject; + if let Err(err) = vm.attach_current_thread(|env| -> jni::errors::Result<()> { + // Initialize JNI bindings + jni_init(env).expect("Failed to initialize JNI bindings"); + + // SAFETY: + // - The reference / pointer is at least valid until we return + // - By creating a `Cast` we ensure we can't accidentally delete the reference + let _activity = unsafe { env.as_cast_raw::>(&activity)? }; + // Do something with the activity on the Java main thread, such as call a method or access a field + Ok(()) + }) { + error!("Failed to interact with Android SDK on Java main thread: {err:?}"); + } -#[no_mangle] + eprintln!( + "android_on_create called on thread {:?}", + std::thread::current().id() + ); + info!( + "android_on_create called on thread {:?}", + std::thread::current().id() + ); +} + +enum ToastDuration { + Short = 0, + Long = 1, +} + +fn send_toast(outer_app: &AndroidApp, msg: impl AsRef, duration: ToastDuration) { + let app = outer_app.clone(); + let msg = msg.as_ref().to_string(); + outer_app.run_on_java_main_thread(Box::new(move || { + // We initialize JavaVM::singleton at the start of `android_main` + let jvm = jni::JavaVM::singleton().expect("Failed to get singleton JavaVM instance"); + // We use `with_top_local_frame` as a minor optimization because it's guaranteed by + // `run_on_java_main_thread` that we already have an underlying JNI attachment and local + // frame. It would also be perfectly reasonable to use `jvm.attach_current_thread()`. + if let Err(err) = jvm.with_top_local_frame(|env| -> jni::errors::Result<()> { + let activity: jni::sys::jobject = app.activity_as_ptr() as _; + let activity = unsafe { env.as_cast_raw::>(&activity)? }; + + let message = JString::new(env, &msg)?; + let toast = Toast::make_text(env, activity.as_ref(), &message, duration as i32)?; + info!("Showing Toast from Rust JNI callback: {msg}"); + toast.show(env)?; + + Ok(()) + }) { + error!("Failed to execute callback on main thread: {err:?}"); + } + })); +} + +// Called on a dedicated Activity main loop thread, spawned after `android_on_create` returns +// May be called multiple times if the activity is destroyed and recreated. +#[unsafe(no_mangle)] fn android_main(app: AndroidApp) { - android_logger::init_once(android_logger::Config::default().with_min_level(log::Level::Info)); + eprintln!( + "android_main started on thread {:?}", + std::thread::current().id() + ); + info!( + "android_main started on thread {:?}", + std::thread::current().id() + ); let mut quit = false; let mut redraw_pending = true; @@ -14,9 +144,11 @@ fn android_main(app: AndroidApp) { let mut combining_accent = None; + send_toast(&app, "Hello from Rust on Android!", ToastDuration::Long); + while !quit { app.poll_events( - Some(std::time::Duration::from_secs(1)), /* timeout */ + Some(std::time::Duration::from_secs(2)), /* timeout */ |event| { match event { PollEvent::Wake => { @@ -40,6 +172,7 @@ fn android_main(app: AndroidApp) { info!("Resumed with saved state = {uri:#?}"); } } + send_toast(&app, "Resumed!", ToastDuration::Short); } MainEvent::InitWindow { .. } => { native_window = app.native_window(); @@ -47,6 +180,7 @@ fn android_main(app: AndroidApp) { } MainEvent::TerminateWindow { .. } => { native_window = None; + redraw_pending = false; } MainEvent::WindowResized { .. } => { redraw_pending = true; @@ -59,8 +193,12 @@ fn android_main(app: AndroidApp) { } MainEvent::ConfigChanged { .. } => { info!("Config Changed: {:#?}", app.config()); + send_toast(&app, "Config Changed!", ToastDuration::Short); + } + MainEvent::LowMemory => { + info!("Low Memory Warning"); + send_toast(&app, "Low Memory!", ToastDuration::Short); } - MainEvent::LowMemory => {} MainEvent::Destroy => quit = true, _ => { /* ... */ } @@ -98,13 +236,54 @@ fn android_main(app: AndroidApp) { let y = pointer.y(); println!("POINTER UP {x}, {y}"); - if x < 200.0 && y < 200.0 { + + if x < 500.0 && y < 500.0 { println!("Requesting to show keyboard"); + send_toast( + &app, + "Requesting to show keyboard", + ToastDuration::Short, + ); app.show_soft_input(true); + } else if x >= 500.0 && y < 500.0 { + println!("Requesting to hide keyboard"); + send_toast( + &app, + "Requesting to hide keyboard", + ToastDuration::Short, + ); + app.hide_soft_input(false); + } else { + send_toast( + &app, + format!("POINTER UP {x}, {y}"), + ToastDuration::Short, + ); } } _ => {} } + let num_pointers = motion_event.pointer_count(); + for i in 0..num_pointers { + let pointer = motion_event.pointer_at_index(i); + + println!( + "Pointer[{i}]: id={}, time={}, x={}, y={}", + pointer.pointer_id(), + motion_event.event_time(), + pointer.x(), + pointer.y(), + ); + for sample in pointer.history() { + println!( + " History[{}]: x={}, y={}, time={:?}", + sample.history_index(), + sample.x(), + sample.y(), + sample.event_time() + ); + } + } } InputEvent::TextEvent(state) => { info!("Input Method State: {state:?}"); @@ -113,6 +292,16 @@ fn android_main(app: AndroidApp) { } info!("Input Event: {event:?}"); + app.run_on_java_main_thread(Box::new(move || { + println!( + "Callback on main thread {:?}", + std::thread::current().id() + ); + info!( + "Callback on main thread {:?}", + std::thread::current().id() + ); + })); InputStatus::Unhandled }) { info!("No more input available"); @@ -120,7 +309,7 @@ fn android_main(app: AndroidApp) { } }, Err(err) => { - log::error!("Failed to get input events iterator: {err:?}"); + error!("Failed to get input events iterator: {err:?}"); } } @@ -148,7 +337,7 @@ fn character_map_and_combine_key( let key_map = match app.device_key_character_map(device_id) { Ok(key_map) => key_map, Err(err) => { - log::error!("Failed to look up `KeyCharacterMap` for device {device_id}: {err:?}"); + error!("Failed to look up `KeyCharacterMap` for device {device_id}: {err:?}"); return None; } }; @@ -160,12 +349,16 @@ fn character_map_and_combine_key( let combined_unicode = if let Some(accent) = combining_accent { match key_map.get_dead_char(*accent, unicode) { Ok(Some(key)) => { - info!("KeyEvent: Combined '{unicode}' with accent '{accent}' to give '{key}'"); + info!( + "KeyEvent: Combined '{unicode}' with accent '{accent}' to give '{key}'" + ); Some(key) } Ok(None) => None, Err(err) => { - log::error!("KeyEvent: Failed to combine 'dead key' accent '{accent}' with '{unicode}': {err:?}"); + error!( + "KeyEvent: Failed to combine 'dead key' accent '{accent}' with '{unicode}': {err:?}" + ); None } } @@ -193,7 +386,7 @@ fn character_map_and_combine_key( None } Err(err) => { - log::error!("KeyEvent: Failed to get key map character: {err:?}"); + error!("KeyEvent: Failed to get key map character: {err:?}"); *combining_accent = None; None } diff --git a/examples/na-mainloop/.gitignore b/examples/na-mainloop/.gitignore index 24ad84c4..810307fe 100644 --- a/examples/na-mainloop/.gitignore +++ b/examples/na-mainloop/.gitignore @@ -1,12 +1,8 @@ *.iml .gradle /local.properties -/.idea/caches -/.idea/libraries -/.idea/modules.xml -/.idea/workspace.xml -/.idea/navEditor.xml -/.idea/assetWizardSettings.xml +/.idea +/.vscode .DS_Store /build /captures diff --git a/examples/na-mainloop/Cargo.lock b/examples/na-mainloop/Cargo.lock new file mode 100644 index 00000000..aca0a0bd --- /dev/null +++ b/examples/na-mainloop/Cargo.lock @@ -0,0 +1,674 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-activity" +version = "0.6.0" +dependencies = [ + "android-properties", + "bitflags", + "cc", + "jni", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys 0.6.0+11769913", + "num_enum", + "thiserror 2.0.18", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cc" +version = "1.2.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "jni" +version = "0.22.4" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom", + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "na-mainloop" +version = "0.1.0" +dependencies = [ + "android-activity", + "jni", + "paranoid-android", + "tracing", + "tracing-log", + "tracing-subscriber", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags", + "jni-sys 0.3.0", + "log", + "ndk-sys 0.6.0+11769913", + "num_enum", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys 0.3.0", +] + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys 0.3.0", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "paranoid-android" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "101795d63d371b43e38d6e7254677657be82f17022f7f7893c268f33ac0caadc" +dependencies = [ + "lazy_static", + "ndk-sys 0.5.0+25.2.9519653", + "sharded-slab", + "smallvec", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd_cesu8" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "toml_datetime" +version = "1.0.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.4+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.9+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +dependencies = [ + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" diff --git a/examples/na-mainloop/Cargo.toml b/examples/na-mainloop/Cargo.toml index f7cea943..663eb4ac 100644 --- a/examples/na-mainloop/Cargo.toml +++ b/examples/na-mainloop/Cargo.toml @@ -1,21 +1,28 @@ [package] name = "na-mainloop" version = "0.1.0" -edition = "2021" +edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -log = "0.4" -android_logger = "0.11.0" -android-activity = { path="../../android-activity", features = [ "native-activity" ] } -ndk-sys = "0.6.0" -ndk = "0.9.0" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = [ + "fmt", + "env-filter", + "tracing-log", +] } +paranoid-android = "0.2" +tracing-log = "0.2" + +android-activity = { path = "../../android-activity", features = [ + "native-activity", +] } +jni = "0.22" [lib] #name="na_mainloop" -crate_type=["cdylib"] - +crate-type = ["cdylib"] #################### # cargo apk config # @@ -23,10 +30,10 @@ crate_type=["cdylib"] [package.metadata.android] # Specifies the package property of the manifest. -package = "com.foo.bar" +package = "com.github.rust_mobile.namainloop" # Specifies the array of targets to build for. -build_targets = [ "aarch64-linux-android" ] +build_targets = ["aarch64-linux-android"] # Path to your application's resources folder. # If not specified, resources will not be included in the APK. @@ -49,9 +56,9 @@ build_targets = [ "aarch64-linux-android" ] # # Defaults to a `min_sdk_version` of 23 and `target_sdk_version` of 30 (or lower if the detected NDK doesn't support this). [package.metadata.android.sdk] -min_sdk_version = 28 -target_sdk_version = 31 -#max_sdk_version = 31 +min_sdk_version = 31 +target_sdk_version = 35 +#max_sdk_version = 35 # See https://developer.android.com/guide/topics/manifest/uses-feature-element # @@ -109,7 +116,7 @@ version = 1 # See https://developer.android.com/guide/topics/manifest/application-element#label # # Defaults to the compiled artifact's name. -label = "Application Name" +label = "NativeActivity Mainloop" # See https://developer.android.com/guide/topics/manifest/meta-data-element # diff --git a/examples/na-mainloop/README.md b/examples/na-mainloop/README.md index 0e73eece..ee152639 100644 --- a/examples/na-mainloop/README.md +++ b/examples/na-mainloop/README.md @@ -19,6 +19,12 @@ cargo ndk -t arm64-v8a -o app/src/main/jniLibs/ build ./gradlew installDebug ``` +Run with: + +``` +adb shell am start -n com.github.realfit_mobile.namainloop/android.app.NativeActivity +``` + # Cargo APK Build ``` export ANDROID_NDK_HOME="path/to/ndk" diff --git a/examples/na-mainloop/android-addr2line.py b/examples/na-mainloop/android-addr2line.py deleted file mode 100644 index fbedcd26..00000000 --- a/examples/na-mainloop/android-addr2line.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/python3 -import sys -import re - -for line in sys.stdin: - search = re.search('#[0-9]+ +pc +([0-9A-Fa-f]+) +', line) - if search != None: - print(search.group(1)) diff --git a/examples/na-mainloop/app/build.gradle b/examples/na-mainloop/app/build.gradle index dd102cc8..19e7de43 100644 --- a/examples/na-mainloop/app/build.gradle +++ b/examples/na-mainloop/app/build.gradle @@ -3,26 +3,23 @@ plugins { } android { - ndkVersion "25.2.9519653" - compileSdk 31 + compileSdk = 35 defaultConfig { - applicationId "co.realfit.namainloop" - minSdk 28 - targetSdk 31 - versionCode 1 - versionName "1.0" - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + applicationId = "com.github.rust_mobile.namainloop" + minSdk = 31 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" } buildTypes { release { - minifyEnabled false + minifyEnabled = false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } debug { - minifyEnabled false + minifyEnabled = false //packagingOptions { // doNotStrip '**/*.so' //} @@ -30,10 +27,10 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } - namespace 'co.realfit.namainloop' + namespace = 'com.github.rust_mobile.namainloop' } dependencies { diff --git a/examples/na-mainloop/app/src/main/AndroidManifest.xml b/examples/na-mainloop/app/src/main/AndroidManifest.xml index d104641c..6b21de13 100644 --- a/examples/na-mainloop/app/src/main/AndroidManifest.xml +++ b/examples/na-mainloop/app/src/main/AndroidManifest.xml @@ -2,15 +2,14 @@ + > diff --git a/examples/na-mainloop/app/src/main/ic_launcher-playstore.png b/examples/na-mainloop/app/src/main/ic_launcher-playstore.png new file mode 100644 index 00000000..55efda2e Binary files /dev/null and b/examples/na-mainloop/app/src/main/ic_launcher-playstore.png differ diff --git a/examples/na-mainloop/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/examples/na-mainloop/app/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 2b068d11..00000000 --- a/examples/na-mainloop/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/examples/na-mainloop/app/src/main/res/drawable/ic_launcher_background.xml b/examples/na-mainloop/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9c..00000000 --- a/examples/na-mainloop/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/na-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/examples/na-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index eca70cfe..036d09bc 100644 --- a/examples/na-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/examples/na-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/examples/na-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/examples/na-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index eca70cfe..036d09bc 100644 --- a/examples/na-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/examples/na-mainloop/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/examples/na-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/examples/na-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher.webp index c209e78e..f08a4124 100644 Binary files a/examples/na-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher.webp and b/examples/na-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/examples/na-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/examples/na-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..a7af7759 Binary files /dev/null and b/examples/na-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ diff --git a/examples/na-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/examples/na-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp index b2dfe3d1..0b9af008 100644 Binary files a/examples/na-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and b/examples/na-mainloop/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/examples/na-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/examples/na-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher.webp index 4f0f1d64..0f38950f 100644 Binary files a/examples/na-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher.webp and b/examples/na-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/examples/na-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/examples/na-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..e4bdf4e3 Binary files /dev/null and b/examples/na-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ diff --git a/examples/na-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/examples/na-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp index 62b611da..9e3cf92d 100644 Binary files a/examples/na-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and b/examples/na-mainloop/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/examples/na-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/examples/na-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher.webp index 948a3070..8d975559 100644 Binary files a/examples/na-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and b/examples/na-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/examples/na-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/examples/na-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..7a7a6a4d Binary files /dev/null and b/examples/na-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ diff --git a/examples/na-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/examples/na-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp index 1b9a6956..d8424d37 100644 Binary files a/examples/na-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and b/examples/na-mainloop/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/examples/na-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/examples/na-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp index 28d4b77f..61526f2a 100644 Binary files a/examples/na-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and b/examples/na-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/examples/na-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/examples/na-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..90692d1a Binary files /dev/null and b/examples/na-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ diff --git a/examples/na-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/examples/na-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp index 9287f508..717f69d4 100644 Binary files a/examples/na-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and b/examples/na-mainloop/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/examples/na-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/examples/na-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp index aa7d6427..1349310f 100644 Binary files a/examples/na-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and b/examples/na-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/examples/na-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/examples/na-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..c055957d Binary files /dev/null and b/examples/na-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ diff --git a/examples/na-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/examples/na-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp index 9126ae37..91c850d2 100644 Binary files a/examples/na-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and b/examples/na-mainloop/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/examples/na-mainloop/app/src/main/res/values/colors.xml b/examples/na-mainloop/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..f8c6127d --- /dev/null +++ b/examples/na-mainloop/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/examples/na-mainloop/app/src/main/res/values/ic_launcher_background.xml b/examples/na-mainloop/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 00000000..ece04f86 --- /dev/null +++ b/examples/na-mainloop/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #C8C49F + \ No newline at end of file diff --git a/examples/na-mainloop/build.gradle b/examples/na-mainloop/build.gradle index 8ba8ae99..e05eb1e9 100644 --- a/examples/na-mainloop/build.gradle +++ b/examples/na-mainloop/build.gradle @@ -1,10 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '8.0.0' apply false - id 'com.android.library' version '8.0.0' apply false + id 'com.android.application' version '9.1.0' apply false + id 'com.android.library' version '9.1.0' apply false } -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/examples/na-mainloop/gradle.properties b/examples/na-mainloop/gradle.properties index ec63151a..a400a79b 100644 --- a/examples/na-mainloop/gradle.properties +++ b/examples/na-mainloop/gradle.properties @@ -1,23 +1,15 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app"s APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn +# Enable Gradle Daemon +org.gradle.daemon=true + +# JVM arguments +org.gradle.jvmargs=-Xmx4g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +# Enable AndroidX android.useAndroidX=true -# Enables namespacing of each library's R class so that its R class includes only the -# resources declared in the library itself and none from the library's dependencies, -# thereby reducing the size of the R class for that library -android.nonTransitiveRClass=true -android.defaults.buildfeatures.buildconfig=true -android.nonFinalResIds=false \ No newline at end of file +# Build caching and parallel execution +org.gradle.caching=true +org.gradle.parallel=true +# Incremental Kotlin compilation +kotlin.incremental=true + +# File system watching for faster builds +org.gradle.unsafe.watch-fs=true \ No newline at end of file diff --git a/examples/na-mainloop/gradle/wrapper/gradle-wrapper.jar b/examples/na-mainloop/gradle/wrapper/gradle-wrapper.jar index e708b1c0..a4b76b95 100644 Binary files a/examples/na-mainloop/gradle/wrapper/gradle-wrapper.jar and b/examples/na-mainloop/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/na-mainloop/gradle/wrapper/gradle-wrapper.properties b/examples/na-mainloop/gradle/wrapper/gradle-wrapper.properties index 5538f03a..37f78a6a 100644 --- a/examples/na-mainloop/gradle/wrapper/gradle-wrapper.properties +++ b/examples/na-mainloop/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ -#Mon May 02 15:39:12 BST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip distributionPath=wrapper/dists -zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/na-mainloop/src/lib.rs b/examples/na-mainloop/src/lib.rs index a2f94e7f..153ef8ab 100644 --- a/examples/na-mainloop/src/lib.rs +++ b/examples/na-mainloop/src/lib.rs @@ -1,12 +1,143 @@ +use std::sync::OnceLock; + use android_activity::{ + AndroidApp, InputStatus, MainEvent, OnCreateState, PollEvent, input::{InputEvent, KeyAction, KeyEvent, KeyMapChar, MotionAction}, - AndroidApp, InputStatus, MainEvent, PollEvent, + ndk, ndk_sys, +}; +use jni::{ + objects::{JObject, JString}, + refs::Global, + vm::JavaVM, }; -use log::info; +use tracing::{error, info}; + +jni::bind_java_type! { Context => "android.content.Context" } +jni::bind_java_type! { + Activity => "android.app.Activity", + type_map { + Context => "android.content.Context", + }, + is_instance_of { + context: Context + }, +} + +jni::bind_java_type! { + Toast => "android.widget.Toast", + type_map { + Context => "android.content.Context", + }, + methods { + static fn make_text(context: Context, text: JCharSequence, duration: i32) -> Toast, + fn show(), + } +} + +// Note: The jni bindings will actually initialize lazily but it can be helpful +// to initialize explicitly to get an up-front error in case there is an issue +// (such as a typo with a method name or incorrect signature) rather than having +// an unpredictable error when using the binding. +fn jni_init(env: &jni::Env) -> jni::errors::Result<()> { + let _ = ContextAPI::get(env, &Default::default())?; + let _ = ActivityAPI::get(env, &Default::default())?; + let _ = ToastAPI::get(env, &Default::default())?; + // .. call other `get` functions for other bindings here as needed ... + Ok(()) +} + +// Called while Activity.onCreate is running +// May be called multiple times if the activity is destroyed and recreated. +#[unsafe(no_mangle)] +fn android_on_create(state: &OnCreateState) { + static ONCE: OnceLock<()> = OnceLock::new(); + ONCE.get_or_init(|| { + use tracing_subscriber::prelude::*; + + unsafe { std::env::set_var("RUST_BACKTRACE", "full") }; + + const DEFAULT_ENV_FILTER: &str = "debug,wgpu_hal=info,winit=info,naga=info"; + let filter_layer = tracing_subscriber::EnvFilter::new(DEFAULT_ENV_FILTER); + let android_layer = paranoid_android::layer(env!("CARGO_PKG_NAME")) + .with_ansi(false) + .with_span_events(tracing_subscriber::fmt::format::FmtSpan::CLOSE) + .with_thread_names(true); + tracing_subscriber::registry() + .with(filter_layer) + .with(android_layer) + .init(); + }); + + let vm = unsafe { JavaVM::from_raw(state.vm_as_ptr().cast()) }; + // Note: from here on we can also rely on `JavaVM::singleton()` now that we know it's been initialized. + + let activity = state.activity_as_ptr() as jni::sys::jobject; + if let Err(err) = vm.attach_current_thread(|env| -> jni::errors::Result<()> { + // Initialize JNI bindings + jni_init(env).expect("Failed to initialize JNI bindings"); + + // SAFETY: + // - The reference / pointer is at least valid until we return + // - By creating a `Cast` we ensure we can't accidentally delete the reference + let _activity = unsafe { env.as_cast_raw::>(&activity)? }; + // Do something with the activity on the Java main thread, such as call a method or access a field + Ok(()) + }) { + error!("Failed to interact with Android SDK on Java main thread: {err:?}"); + } -#[no_mangle] + eprintln!( + "android_on_create called on thread {:?}", + std::thread::current().id() + ); + info!( + "android_on_create called on thread {:?}", + std::thread::current().id() + ); +} + +enum ToastDuration { + Short = 0, + Long = 1, +} + +fn send_toast(outer_app: &AndroidApp, msg: impl AsRef, duration: ToastDuration) { + let app = outer_app.clone(); + let msg = msg.as_ref().to_string(); + outer_app.run_on_java_main_thread(Box::new(move || { + // We initialize JavaVM::singleton at the start of `android_main` + let jvm = jni::JavaVM::singleton().expect("Failed to get singleton JavaVM instance"); + // We use `with_top_local_frame` as a minor optimization because it's guaranteed by + // `run_on_java_main_thread` that we already have an underlying JNI attachment and local + // frame. It would also be perfectly reasonable to use `jvm.attach_current_thread()`. + if let Err(err) = jvm.with_top_local_frame(|env| -> jni::errors::Result<()> { + let activity: jni::sys::jobject = app.activity_as_ptr() as _; + let activity = unsafe { env.as_cast_raw::>(&activity)? }; + + let message = JString::new(env, &msg)?; + let toast = Toast::make_text(env, activity.as_ref(), &message, duration as i32)?; + info!("Showing Toast from Rust JNI callback: {msg}"); + toast.show(env)?; + + Ok(()) + }) { + error!("Failed to execute callback on main thread: {err:?}"); + } + })); +} + +// Called on a dedicated Activity main loop thread, spawned after `android_on_create` returns +// May be called multiple times if the activity is destroyed and recreated. +#[unsafe(no_mangle)] fn android_main(app: AndroidApp) { - android_logger::init_once(android_logger::Config::default().with_min_level(log::Level::Info)); + eprintln!( + "android_main started on thread {:?}", + std::thread::current().id() + ); + info!( + "android_main started on thread {:?}", + std::thread::current().id() + ); let mut quit = false; let mut redraw_pending = true; @@ -14,9 +145,11 @@ fn android_main(app: AndroidApp) { let mut combining_accent = None; + send_toast(&app, "Hello from Rust on Android!", ToastDuration::Long); + while !quit { app.poll_events( - Some(std::time::Duration::from_secs(1)), /* timeout */ + Some(std::time::Duration::from_secs(2)), /* timeout */ |event| { match event { PollEvent::Wake => { @@ -40,6 +173,7 @@ fn android_main(app: AndroidApp) { info!("Resumed with saved state = {uri:#?}"); } } + send_toast(&app, "Resumed!", ToastDuration::Short); } MainEvent::InitWindow { .. } => { native_window = app.native_window(); @@ -47,6 +181,7 @@ fn android_main(app: AndroidApp) { } MainEvent::TerminateWindow { .. } => { native_window = None; + redraw_pending = false; } MainEvent::WindowResized { .. } => { redraw_pending = true; @@ -59,8 +194,12 @@ fn android_main(app: AndroidApp) { } MainEvent::ConfigChanged { .. } => { info!("Config Changed: {:#?}", app.config()); + send_toast(&app, "Config Changed!", ToastDuration::Short); + } + MainEvent::LowMemory => { + info!("Low Memory Warning"); + send_toast(&app, "Low Memory!", ToastDuration::Short); } - MainEvent::LowMemory => {} MainEvent::Destroy => quit = true, _ => { /* ... */ } @@ -98,13 +237,54 @@ fn android_main(app: AndroidApp) { let y = pointer.y(); println!("POINTER UP {x}, {y}"); - if x < 200.0 && y < 200.0 { + + if x < 500.0 && y < 500.0 { println!("Requesting to show keyboard"); + send_toast( + &app, + "Requesting to show keyboard", + ToastDuration::Short, + ); app.show_soft_input(true); + } else if x >= 500.0 && y < 500.0 { + println!("Requesting to hide keyboard"); + send_toast( + &app, + "Requesting to hide keyboard", + ToastDuration::Short, + ); + app.hide_soft_input(false); + } else { + send_toast( + &app, + format!("POINTER UP {x}, {y}"), + ToastDuration::Short, + ); } } _ => {} } + let num_pointers = motion_event.pointer_count(); + for i in 0..num_pointers { + let pointer = motion_event.pointer_at_index(i); + + println!( + "Pointer[{i}]: id={}, time={}, x={}, y={}", + pointer.pointer_id(), + motion_event.event_time(), + pointer.x(), + pointer.y(), + ); + for sample in pointer.history() { + println!( + " History[{}]: x={}, y={}, time={:?}", + sample.history_index(), + sample.x(), + sample.y(), + sample.event_time() + ); + } + } } InputEvent::TextEvent(state) => { info!("Input Method State: {state:?}"); @@ -113,6 +293,16 @@ fn android_main(app: AndroidApp) { } info!("Input Event: {event:?}"); + app.run_on_java_main_thread(Box::new(move || { + println!( + "Callback on main thread {:?}", + std::thread::current().id() + ); + info!( + "Callback on main thread {:?}", + std::thread::current().id() + ); + })); InputStatus::Unhandled }) { info!("No more input available"); @@ -120,7 +310,7 @@ fn android_main(app: AndroidApp) { } }, Err(err) => { - log::error!("Failed to get input events iterator: {err:?}"); + error!("Failed to get input events iterator: {err:?}"); } } @@ -148,7 +338,7 @@ fn character_map_and_combine_key( let key_map = match app.device_key_character_map(device_id) { Ok(key_map) => key_map, Err(err) => { - log::error!("Failed to look up `KeyCharacterMap` for device {device_id}: {err:?}"); + error!("Failed to look up `KeyCharacterMap` for device {device_id}: {err:?}"); return None; } }; @@ -160,12 +350,16 @@ fn character_map_and_combine_key( let combined_unicode = if let Some(accent) = combining_accent { match key_map.get_dead_char(*accent, unicode) { Ok(Some(key)) => { - info!("KeyEvent: Combined '{unicode}' with accent '{accent}' to give '{key}'"); + info!( + "KeyEvent: Combined '{unicode}' with accent '{accent}' to give '{key}'" + ); Some(key) } Ok(None) => None, Err(err) => { - log::error!("KeyEvent: Failed to combine 'dead key' accent '{accent}' with '{unicode}': {err:?}"); + error!( + "KeyEvent: Failed to combine 'dead key' accent '{accent}' with '{unicode}': {err:?}" + ); None } } @@ -193,7 +387,7 @@ fn character_map_and_combine_key( None } Err(err) => { - log::error!("KeyEvent: Failed to get key map character: {err:?}"); + error!("KeyEvent: Failed to get key map character: {err:?}"); *combining_accent = None; None }