Compare commits

...

84 Commits

Author SHA1 Message Date
Jason A. Donenfeld 09b75c2bd3 version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2026-01-02 03:37:18 +01:00
Jason A. Donenfeld 2a01764282 tunnel: also bump the minsdk of this module
Fixes: 3b6ab660 ("ui: raise min SDK to 24")
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2026-01-02 03:34:42 +01:00
Jason A. Donenfeld 3f30378c73 tunnel: newIncompleteFuture requires API 31
Fixes: 3b6ab660 ("ui: raise min SDK to 24")
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2026-01-02 03:33:27 +01:00
Jason A. Donenfeld a494c62bd9 version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-12-31 13:11:08 +01:00
Jason A. Donenfeld 743b28bb85 Updater: don't compile in updater when it can't be used
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-12-31 13:06:45 +01:00
Jason A. Donenfeld 1c0b211bd6 LogViewerActivity: remove unnecessary ?.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-12-31 12:23:59 +01:00
Jason A. Donenfeld 5e88cd24c5 build: upgrade all dependencies
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-12-31 12:15:42 +01:00
Harsh Shandilya 3b6ab660a9 ui: raise min SDK to 24
The difference between the usage of 21 and 24 is not big enough to hold
on to all the baggage from API 21

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-10-20 18:22:36 +02:00
Brandon T 0d18e478ca tunnel: add isAlwaysOn and isLockdownEnabled
Signed-off-by: Brandon T <JustBrandonT@gmail.com>
[Harsh: fix build and Javadoc errors]
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-10-20 18:22:36 +02:00
Anthony Ryan 89c0bb6c7a ui: losslessly optimize launcher icons
Using Efficient-Comprression-Tool we can reduce image size  by 37.59KB (27%)
with no visual change.

      compressed      │     uncompressed      │
──────────┬───────────┼───────────┬───────────┤
 size     │ diff      │ size      │ diff      │ path
──────────┼───────────┼───────────┼───────────┼───────────────────────────────────────────────
 75.2 KiB │ +75.2 KiB │       0 B │       0 B │ +
 15.8 KiB │  -6.7 KiB │  15.7 KiB │  -6.7 KiB │ ∆ res/mipmap-xxxhdpi-v4/ic_launcher.png
 20.4 KiB │  -6.3 KiB │  20.3 KiB │  -6.3 KiB │ ∆ res/mipmap-xxxhdpi-v4/ic_launcher_round.png
  8.6 KiB │  -6.2 KiB │   8.4 KiB │  -6.2 KiB │ ∆ res/mipmap-xhdpi-v4/banner.png
 11.6 KiB │  -4.3 KiB │  11.5 KiB │  -4.3 KiB │ ∆ res/mipmap-xxhdpi-v4/ic_launcher.png
 15.2 KiB │    -4 KiB │  15.1 KiB │    -4 KiB │ ∆ res/mipmap-xxhdpi-v4/ic_launcher_round.png
  6.2 KiB │  -2.6 KiB │   6.1 KiB │  -2.6 KiB │ ∆ res/mipmap-xhdpi-v4/ic_launcher.png
  7.9 KiB │  -2.5 KiB │   7.8 KiB │  -2.5 KiB │ ∆ res/mipmap-xhdpi-v4/ic_launcher_round.png
    5 KiB │  -1.7 KiB │   4.9 KiB │  -1.7 KiB │ ∆ res/mipmap-hdpi-v4/ic_launcher.png
    6 KiB │  -1.5 KiB │   5.8 KiB │  -1.5 KiB │ ∆ res/mipmap-hdpi-v4/ic_launcher_round.png
  2.7 KiB │  -1,002 B │   2.5 KiB │    -996 B │ ∆ res/mipmap-mdpi-v4/ic_launcher.png
  3.2 KiB │    -918 B │   3.1 KiB │    -918 B │ ∆ res/mipmap-mdpi-v4/ic_launcher_round.png
──────────┼───────────┼───────────┼───────────┼───────────────────────────────────────────────
  178 KiB │ +37.6 KiB │ 101.1 KiB │ -37.6 KiB │ (total)

[0]: https://github.com/JakeWharton/diffuse/

Signed-off-by: Anthony Ryan <anthonyryan1@gmail.com>
[Harsh: comparing APKs with Diffuse[0] shows modest but non-zero size savings]
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2025-10-20 18:22:36 +02:00
Harsh Shandilya 705ebdb19c build: upgrade all dependencies
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-10-20 18:22:36 +02:00
Harsh Shandilya b5411b8c57 gradle: upgrade to 9.1.0
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-10-20 18:22:36 +02:00
Harsh Shandilya 9438b9d7f4 build(tunnel): update publishing setup for OSSRH deprecation
The newly added zipReleasePublication task will generate a ZIP file at tunnel/build/distributions/tunnel-$VERSION-maven.zip
that can be uploaded to https://central.sonatype.com/publishing.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-10-20 18:22:36 +02:00
Jason A. Donenfeld f0b45d50f3 version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-31 04:22:08 +02:00
Jason A. Donenfeld cb216c6ec6 QrCodeFromFileScanner: more efficiently downscale images and release memory
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-31 04:22:06 +02:00
Jason A. Donenfeld d45b1ea9a7 QrCodeFromFileScanner: catch OOM errors
OutOfMemoryError is an Error which is a Throwable, but it isn't an
exception. Try to catch it for downscaling by catching all Throwables.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-31 03:47:10 +02:00
Jason A. Donenfeld f9764e9592 gradle: bump dependencies
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-31 03:43:04 +02:00
Jason A. Donenfeld 6414de156c QuickTileService: wait for tunnels to load
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-28 03:56:51 +02:00
Jason A. Donenfeld fa989fe58e QuickTileService: handle onClick in applicationScope
This helps with the case where the TunnelManager is still loading.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-28 03:49:37 +02:00
Jason A. Donenfeld 1310a513d8 version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-23 04:19:29 +02:00
Jason A. Donenfeld 90395232b0 TvMainActivity: link to cx file explorer
Google requires us to link to a specific file manager. We can't just
open the app store. They keep rejecting the app otherwise. Annoying.

Also, due to Android TV bugs, we also can't link to a prefilled search
query of "file manager". Instead we must link to an actual file manager.

Unfortunately, none of the open source file manager apps both support
the TV interface and can act as a file chooser. So instead we pick what
looks like the only decent one that doesn't have any in app purchases.
Ugh. I don't like doing this. It's not an endorsement. I don't know much
about who makes these. But what choice do we have?

So doing this for now. Maybe we'll find some better solution or apply to
be a file manager ourselves in the future.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-23 04:16:41 +02:00
Jason A. Donenfeld b9969891b8 version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-22 01:46:37 +02:00
Jason A. Donenfeld 559112998f tools: bump to wireguard-go 0.0.20250522 for major regression
Things were broken on kernels [4.19, 5.12).

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-22 01:46:10 +02:00
Jason A. Donenfeld e12e658408 DonatePreferences: use toUri() extension
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-21 01:48:42 +02:00
Jason A. Donenfeld a57ca57e6c tools: align to 16k
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-21 01:46:01 +02:00
Jason A. Donenfeld f3f30030b9 tools: bump wireguard-tools to 1.0.20250521
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-21 01:35:38 +02:00
Jason A. Donenfeld c417bb8d7c version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-19 18:14:43 +02:00
Jason A. Donenfeld 567fd6ae96 gradle: update to agp 8.10
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-19 18:11:00 +02:00
Jason A. Donenfeld 2c223fb68c MainActivity: don't reuse id names across layouts
This causes problems on foldables.

Reported-by: Josh Dague <josh3736@gmail.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-19 17:57:39 +02:00
Jason A. Donenfeld 0ea6cee192 global: add missing xml copyright and opening tag
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-19 17:40:03 +02:00
Jason A. Donenfeld 0295abd808 global: update copyright notices
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-19 17:31:02 +02:00
Jason A. Donenfeld 0350b801b6 TunnelCreatorActivity: use proper xml for layout
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-19 17:26:38 +02:00
Jason A. Donenfeld 4061003ef8 version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-16 18:49:22 +02:00
Jason A. Donenfeld 3240bd13a8 gradle: update agp to 8.9.3
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-16 18:49:04 +02:00
Jason A. Donenfeld 720079bdf9 TunnelToggleActivity: suppress errors from prepare() in lockdown mode
Exception java.lang.IllegalStateException: Unavailable in lockdown mode
  at android.os.Parcel.createExceptionOrNull (Parcel.java:3031)
  at android.os.Parcel.createException (Parcel.java:3007)
  at android.os.Parcel.readException (Parcel.java:2990)
  at android.os.Parcel.readException (Parcel.java:2932)
  at android.net.IVpnManager$Stub$Proxy.prepareVpn (IVpnManager.java:1064)
  at android.net.VpnService.prepare (VpnService.java:290)
  at com.wireguard.android.activity.TunnelToggleActivity$onCreate$1.invokeSuspend (TunnelToggleActivity.kt:44)
  at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:8)
  at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith (DispatchedContinuation.kt:155)
  at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable (Cancellable.kt:12)
  at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default (Cancellable.kt:12)
  at kotlinx.coroutines.CoroutineStart.invoke (CoroutineStart.java:80)
  at kotlinx.coroutines.AbstractCoroutine.start (AbstractCoroutine.kt:80)
  at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch (BuildersKt__Builders_common.kt:52)
  at kotlinx.coroutines.BuildersKt.launch (Builders.kt:52)
  at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default (BuildersKt__Builders_common.kt:52)
  at kotlinx.coroutines.BuildersKt.launch$default (Builders.kt:52)
  at com.wireguard.android.activity.TunnelToggleActivity.onCreate (TunnelToggleActivity.kt:14)
  at android.app.Activity.performCreate (Activity.java:8591)
  at android.app.Activity.performCreate (Activity.java:8570)
  at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1384)
  at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:4150)
  at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:4325)
  at android.app.servertransaction.LaunchActivityItem.execute (LaunchActivityItem.java:101)
  at android.app.servertransaction.TransactionExecutor.executeCallbacks (TransactionExecutor.java:135)
  at android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:95)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2574)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loopOnce (Looper.java:226)
  at android.os.Looper.loop (Looper.java:313)
  at android.app.ActivityThread.main (ActivityThread.java:8762)
  at java.lang.reflect.Method.invoke
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:604)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067)

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-16 18:45:19 +02:00
Jason A. Donenfeld aa68b5152e ui: set fitsSystemWindows=true for EdgeToEdge on API 35+
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-16 18:41:56 +02:00
Jason A. Donenfeld 67db72ac40 TvMainActivity: use OpenDocument instead of GetContent
This should make it possible to open files on Android TV 14.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-16 18:41:56 +02:00
Jason A. Donenfeld 452a339b37 version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-15 17:21:52 +02:00
Jason A. Donenfeld 7c743534a5 ui: sync translations
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-15 17:20:31 +02:00
Jason A. Donenfeld 4df25dd567 build: crowdin now requires auth
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-15 17:20:08 +02:00
Jason A. Donenfeld 4510fa7482 tools: bump wireguard-go version to latest release
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-15 16:55:19 +02:00
Jason A. Donenfeld 6aab7cccf9 LogViewerActivity: cast array to Any type instead of using union inference
Type argument for reified type parameter 'T' was inferred to the
intersection of ['Comparable<*>' & 'Serializable']. Reification of an
intersection type results in the common supertype being used. This may
lead to subtle issues and an explicit type argument is encouraged. This
will become an error in a future release.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-08 04:59:37 +02:00
Jason A. Donenfeld e7d9beaef8 tools: bump go version
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-08 04:59:37 +02:00
Jason A. Donenfeld bd0967e36e SettingsActivity: manually apply insets for api 35
The forced EdgeToEdge changes don't work well with
PreferenceFragmentCompat, because it's basically abandoned by androidx,
so apply the insets manually ourselves.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-08 04:59:37 +02:00
Jason A. Donenfeld de2338a470 SettingsActivity: remove unused imports
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-08 04:59:37 +02:00
Jason A. Donenfeld c9353a89d4 gradle: remove experimental options now on by default
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-08 04:59:37 +02:00
Jason A. Donenfeld fb115b4079 gradle: use = instead of .set
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-08 04:59:37 +02:00
Jason A. Donenfeld 0740e86cb2 gradle: bump deps
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-08 04:59:37 +02:00
Jason A. Donenfeld 9c0bafad17 gradle: update kotlin to 2.1.20
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-05 16:09:58 +02:00
Jason A. Donenfeld d7242288bb gradle: target API 36
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-05 16:09:58 +02:00
Jason A. Donenfeld 3e1bf5f9e9 tools: bump wg-go
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-05 15:44:24 +02:00
Jason A. Donenfeld 55d6ad6c95 gradle: update to agp 8.9.2 and gradle 8.14
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2025-05-05 15:44:24 +02:00
Jason A. Donenfeld 0a8de709b6 version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-10-18 14:26:45 +02:00
Jason A. Donenfeld 83c382b6cc tools: bump go
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-10-18 14:26:41 +02:00
Jason A. Donenfeld 9453b6c0e2 ui: sync with crowdin
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-10-18 14:26:41 +02:00
Jason A. Donenfeld 8390553850 QuickTileService: require SYSTEM_ALERT_WINDOW to start background activity
Due to buggy changes in Android 14, we now need to bother the user about
enabling "draw over other apps" for the quick settings toggle to work
when the app isn't already running.

Link: https://issuetracker.google.com/issues/305035828
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-10-18 14:26:41 +02:00
Jason A. Donenfeld db7f70736f gradle: bump many deps
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-10-13 21:32:16 +02:00
Jason A. Donenfeld d4c8f1dfdd gradle: update to agp 8.2.0-beta06
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-10-13 21:24:42 +02:00
Harsh Shandilya db52515dc6 gradle: upgrade to 8.3
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-09-12 12:28:02 +05:30
SlipkHunter 0be12b8d07 ui: only show a snackbar for Android 12 and lower
Signed-off-by: SlipkHunter <abrito025@gmail.com>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-09-12 12:23:46 +05:30
Harsh Shandilya 56be913fa4 gradle: upgrade AGP and Kotlin
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-08-04 20:20:46 +05:30
Harsh Shandilya 82bcac55fb gradle: upgrade to 8.2.1
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-08-04 20:20:46 +05:30
Jason A. Donenfeld 04e503c9db version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-07-07 05:06:04 +02:00
Jason A. Donenfeld 434534ac59 ui: hide corrupted message if no installer
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-07-07 05:06:04 +02:00
Jason A. Donenfeld 0f77af85d3 ui: sync with crowdin
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-07-07 04:24:14 +02:00
Jason A. Donenfeld 58789d6372 version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-07-06 19:05:55 +02:00
Jason A. Donenfeld adefd16f7e ui: remove unused elvis operators
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-07-06 19:05:52 +02:00
Jason A. Donenfeld e4a49a5356 ui: use api 34's startActivityAndCollapse
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-07-06 19:05:52 +02:00
Jason A. Donenfeld 353679801e tunnel: use record class where possible
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-07-05 18:16:53 +02:00
Jason A. Donenfeld 58ec110360 gradle: remove unused import
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-07-05 17:59:01 +02:00
Jason A. Donenfeld a7ce5ad42a gradle: bump to api 34
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-07-05 16:13:19 +02:00
Jason A. Donenfeld 52c0d1ea29 gradle: update to agp 8.2.0-alpha10
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-07-05 16:00:40 +02:00
Jason A. Donenfeld a5b4b9c428 tunnel: add quotes around calling package
Judging by the previous check, this was clearly intended.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-06-08 15:04:39 +02:00
Jason A. Donenfeld e744ce4569 gradle: update to agp 8.2.0-alpha07
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-06-08 15:03:05 +02:00
Jason A. Donenfeld adfd8e247b tunnel: account for recent magisk using UID in sql
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-06-06 03:08:59 +02:00
Jason A. Donenfeld e9243c403a version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-05-26 16:23:49 +02:00
Jason A. Donenfeld fbcbfbd311 strings: sync with crowdin
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-05-26 16:19:52 +02:00
Jason A. Donenfeld dc1d294a82 gradle: bump to core-ktx 1.10.1
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-05-26 16:19:52 +02:00
Jason A. Donenfeld 2abd426cdc gradle: bump to agp 8.2.0-alpha05
I wanted to stay on 8.1 in hopes of landing on a stable channel, but
Google won't backport the RB fix, so we have to bump to 8.2 alphas.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-05-26 16:19:52 +02:00
Jason A. Donenfeld c536f5cc7f gradle: bump to agp 8.1.0-beta03
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-05-26 16:19:52 +02:00
Jason A. Donenfeld 37a892a2da gradle: sort extracted locales rather than generated XML
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-05-26 16:19:52 +02:00
Jason A. Donenfeld f2d166a6a4 ui: add basic double update guard
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-05-26 16:19:52 +02:00
Jason A. Donenfeld d883802178 ui: remove debug keys
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-05-26 16:19:52 +02:00
Jason A. Donenfeld 8d990be204 ui: add missing article to string
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-05-14 01:18:12 +02:00
205 changed files with 2039 additions and 733 deletions
+2 -2
View File
@@ -7,7 +7,7 @@ plugins {
tasks {
wrapper {
gradleVersion = "8.1.1"
distributionSha256Sum = "e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f"
gradleVersion = "8.14"
distributionSha256Sum = "61ad310d3c7d3e5da131b76bbf22b5a4c0786e9d892dae8c1658d4b484de3caa"
}
}
+2 -26
View File
@@ -1,5 +1,5 @@
wireguardVersionCode=505
wireguardVersionName=1.0.20230512
wireguardVersionCode=518
wireguardVersionName=1.0.20260102
wireguardPackageName=com.wireguard.android
# When configured, Gradle will run in incubating parallel mode.
@@ -22,38 +22,15 @@ org.gradle.jvmargs=-Xmx1536m
# Turn off AP discovery in compile path to enable compile avoidance
kapt.include.compile.classpath=false
# Enable non-transitive R class namespacing where each library only contains
# references to the resources it declares instead of declarations plus all
# transitive dependency references.
android.nonTransitiveRClass=true
# Experimental AGP flags
# Generate compile-time only R class for app modules.
android.enableAppCompileTimeRClass=true
# Keep AAPT2 daemons alive between incremental builds.
android.keepWorkerActionServicesBetweenBuilds=true
# Make R fields non-final to improve build speeds.
# http://tools.android.com/tips/non-constant-fields
android.nonFinalResIds=true
# Enable the newly refactored resource shrinker.
android.experimental.enableNewResourceShrinker=true
# Enable precise shrinking in the new resource shrinker.
android.experimental.enableNewResourceShrinker.preciseShrinking=true
# Generate manifest class as a .class directly rather than a Java source file.
android.generateManifestClass=true
# Generate the text map of source sets and absolute paths to allow
# generating relative paths from absolute paths later in the build.
android.experimental.enableSourceSetPathsMap=true
# Use relative paths for better Gradle caching of library build tasks
android.experimental.cacheCompileLibResources=true
# Default Android build features
# Disable BuildConfig generation by default
android.defaults.buildfeatures.buildconfig=false
# Disable AIDL stub generation by default
android.defaults.buildfeatures.aidl=false
# Disable RenderScript compilation by default
android.defaults.buildfeatures.renderscript=false
# Disable resource values generation by default in libraries
android.defaults.buildfeatures.resvalues=false
# Disable shader compilation by default
@@ -63,7 +40,6 @@ android.library.defaults.buildfeatures.androidresources=false
# Suppress warnings for some features that aren't yet stabilized
android.suppressUnsupportedOptionWarnings=android.keepWorkerActionServicesBetweenBuilds,\
android.experimental.enableNewResourceShrinker.preciseShrinking,\
android.enableAppCompileTimeRClass,\
android.suppressUnsupportedOptionWarnings
+16 -16
View File
@@ -1,25 +1,25 @@
[versions]
agp = "8.1.0-beta02"
kotlin = "1.8.21"
agp = "8.13.2"
kotlin = "2.3.0"
[libraries]
androidx-activity-ktx = "androidx.activity:activity-ktx:1.7.1"
androidx-annotation = "androidx.annotation:annotation:1.6.0"
androidx-appcompat = "androidx.appcompat:appcompat:1.6.1"
androidx-activity-ktx = "androidx.activity:activity-ktx:1.12.2"
androidx-annotation = "androidx.annotation:annotation:1.9.1"
androidx-appcompat = "androidx.appcompat:appcompat:1.7.1"
androidx-biometric = "androidx.biometric:biometric:1.1.0"
androidx-collection = "androidx.collection:collection:1.2.0"
androidx-constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4"
androidx-coordinatorlayout = "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
androidx-core-ktx = "androidx.core:core-ktx:1.10.0"
androidx-datastore-preferences = "androidx.datastore:datastore-preferences:1.0.0"
androidx-fragment-ktx = "androidx.fragment:fragment-ktx:1.5.7"
androidx-lifecycle-runtime-ktx = "androidx.lifecycle:lifecycle-runtime-ktx:2.6.1"
androidx-preference-ktx = "androidx.preference:preference-ktx:1.2.0"
desugarJdkLibs = "com.android.tools:desugar_jdk_libs:2.0.3"
google-material = "com.google.android.material:material:1.9.0"
androidx-collection = "androidx.collection:collection:1.5.0"
androidx-constraintlayout = "androidx.constraintlayout:constraintlayout:2.2.1"
androidx-coordinatorlayout = "androidx.coordinatorlayout:coordinatorlayout:1.3.0"
androidx-core-ktx = "androidx.core:core-ktx:1.17.0"
androidx-datastore-preferences = "androidx.datastore:datastore-preferences:1.2.0"
androidx-fragment-ktx = "androidx.fragment:fragment-ktx:1.8.9"
androidx-lifecycle-runtime-ktx = "androidx.lifecycle:lifecycle-runtime-ktx:2.10.0"
androidx-preference-ktx = "androidx.preference:preference-ktx:1.2.1"
desugarJdkLibs = "com.android.tools:desugar_jdk_libs:2.1.5"
google-material = "com.google.android.material:material:1.13.0"
jsr305 = "com.google.code.findbugs:jsr305:3.0.2"
junit = "junit:junit:4.13.2"
kotlinx-coroutines-android = "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.0"
kotlinx-coroutines-android = "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2"
zxing-android-embedded = "com.journeyapps:zxing-android-embedded:4.3.0"
[plugins]
Binary file not shown.
+3 -2
View File
@@ -1,7 +1,8 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
distributionSha256Sum=a17ddd85a26b6a7f5ddb71ff8b05fc5104c0202c6e64782429790c933686c806
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+18 -15
View File
@@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
# Copyright © 2015 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,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# 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/.
@@ -83,7 +85,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# 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\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -111,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -130,10 +132,13 @@ 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.
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.
@@ -141,7 +146,7 @@ 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=SC3045
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@@ -149,7 +154,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -166,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -198,16 +202,15 @@ fi
# 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, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# Collect all arguments for the java command:
# * DEFAULT_JVM_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 \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
+1 -1
View File
@@ -9,7 +9,7 @@ pluginManagement {
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS
repositories {
google()
mavenCentral()
+7 -1
View File
@@ -1,4 +1,10 @@
#!/bin/bash
if [[ $# -ne 1 ]]; then
echo "Download https://crowdin.com/backend/download/project/wireguard.zip and provide path as argument"
exit 1
fi
set -ex
curl -Lo - https://crowdin.com/backend/download/project/wireguard.zip | bsdtar -C ui/src/main/res -x -f - --strip-components 5 wireguard-android
bsdtar -C ui/src/main/res -x -f "$1" --strip-components 5 wireguard-android
find ui/src/main/res -name strings.xml -exec bash -c '[[ $(xmllint --xpath "count(//resources/*)" {}) -ne 0 ]] || rm -rf "$(dirname {})"' \;
+36 -21
View File
@@ -1,6 +1,7 @@
@file:Suppress("UnstableApiUsage")
import org.gradle.api.tasks.testing.logging.TestLogEvent
import org.gradle.api.tasks.bundling.Zip
val pkg: String = providers.gradleProperty("wireguardPackageName").get()
@@ -11,14 +12,14 @@ plugins {
}
android {
compileSdk = 33
compileSdk = 36
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
namespace = "${pkg}.tunnel"
defaultConfig {
minSdk = 21
minSdk = 24
}
externalNativeBuild {
cmake {
@@ -34,6 +35,7 @@ android {
cmake {
targets("libwg-go.so", "libwg.so", "libwg-quick.so")
arguments("-DGRADLE_USER_HOME=${project.gradle.gradleUserHomeDir}")
arguments("-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON")
}
}
}
@@ -81,30 +83,30 @@ publishing {
from(components["release"])
}
pom {
name.set("WireGuard Tunnel Library")
description.set("Embeddable tunnel library for WireGuard for Android")
url.set("https://www.wireguard.com/")
name = "WireGuard Tunnel Library"
description = "Embeddable tunnel library for WireGuard for Android"
url = "https://www.wireguard.com/"
licenses {
license {
name.set("The Apache Software License, Version 2.0")
url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
distribution.set("repo")
name = "The Apache Software License, Version 2.0"
url = "http://www.apache.org/licenses/LICENSE-2.0.txt"
distribution = "repo"
}
}
scm {
connection.set("scm:git:https://git.zx2c4.com/wireguard-android")
developerConnection.set("scm:git:https://git.zx2c4.com/wireguard-android")
url.set("https://git.zx2c4.com/wireguard-android")
connection = "scm:git:https://git.zx2c4.com/wireguard-android"
developerConnection = "scm:git:https://git.zx2c4.com/wireguard-android"
url = "https://git.zx2c4.com/wireguard-android"
}
developers {
organization {
name.set("WireGuard")
url.set("https://www.wireguard.com/")
name = "WireGuard"
url = "https://www.wireguard.com/"
}
developer {
name.set("WireGuard")
email.set("team@wireguard.com")
name = "WireGuard"
email = "team@wireguard.com"
}
}
}
@@ -112,16 +114,29 @@ publishing {
}
repositories {
maven {
name = "sonatype"
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = providers.environmentVariable("SONATYPE_USER").orNull
password = providers.environmentVariable("SONATYPE_PASSWORD").orNull
}
name = "SonatypeUpload"
setUrl(layout.buildDirectory.dir("sonatype"))
}
}
}
val releasePublication = publishing.publications.named("release").get() as MavenPublication
val mavenGroupPath = releasePublication.groupId.replace('.', '/')
val mavenArtifactId = releasePublication.artifactId
val mavenVersion = releasePublication.version
tasks.register<Zip>("zipReleasePublication") {
dependsOn(tasks.named("publishReleasePublicationToSonatypeUploadRepository"))
group = "distribution"
description = "Zips the release publication in Maven repository layout."
val sourceDir = layout.buildDirectory.dir("sonatype/${mavenGroupPath}/${mavenArtifactId}/${mavenVersion}")
from(sourceDir)
archiveFileName.set("${mavenArtifactId}-${mavenVersion}-maven.zip")
destinationDirectory.set(layout.buildDirectory.dir("distributions"))
into("${mavenGroupPath}/${mavenArtifactId}/${mavenVersion}")
}
signing {
useGpgCmd()
sign(publishing.publications)
+1 -1
View File
@@ -1,5 +1,5 @@
<!--
~ Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
~ SPDX-License-Identifier: Apache-2.0
-->
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -52,6 +52,28 @@ public interface Backend {
*/
String getVersion() throws Exception;
/**
* Determines whether the service is running in always-on VPN mode.
* In this mode the system ensures that the service is always running by restarting it when necessary,
* e.g. after reboot.
*
* @return A boolean indicating whether the service is running in always-on VPN mode.
* @throws Exception Exception raised while retrieving the always-on status.
*/
boolean isAlwaysOn() throws Exception;
/**
* Determines whether the service is running in always-on VPN lockdown mode.
* In this mode the system ensures that the service is always running and that the apps
* aren't allowed to bypass the VPN.
*
* @return A boolean indicating whether the service is running in always-on VPN lockdown mode.
* @throws Exception Exception raised while retrieving the lockdown status.
*/
boolean isLockdownEnabled() throws Exception;
/**
* Set the state of a tunnel, updating it's configuration. If the tunnel is already up, config
* may update the running configuration; config may be null when setting the tunnel down.
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -24,12 +24,10 @@ import com.wireguard.crypto.KeyFormatException;
import com.wireguard.util.NonNullForAll;
import java.net.InetAddress;
import java.time.Instant;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -45,7 +43,7 @@ public final class GoBackend implements Backend {
private static final int DNS_RESOLUTION_RETRIES = 10;
private static final String TAG = "WireGuard/GoBackend";
@Nullable private static AlwaysOnCallback alwaysOnCallback;
private static GhettoCompletableFuture<VpnService> vpnService = new GhettoCompletableFuture<>();
private static CompletableFuture<VpnService> vpnService = new CompletableFuture<>();
private final Context context;
@Nullable private Config currentConfig;
@Nullable private Tunnel currentTunnel;
@@ -188,6 +186,24 @@ public final class GoBackend implements Backend {
return wgVersion();
}
/**
* Determines if the service is running in always-on VPN mode.
* @return {@link boolean} whether the service is running in always-on VPN mode.
*/
@Override
public boolean isAlwaysOn() throws ExecutionException, InterruptedException, TimeoutException {
return vpnService.get(0, TimeUnit.NANOSECONDS).isAlwaysOn();
}
/**
* Determines if the service is running in always-on VPN lockdown mode.
* @return {@link boolean} whether the service is running in always-on VPN lockdown mode.
*/
@Override
public boolean isLockdownEnabled() throws ExecutionException, InterruptedException, TimeoutException {
return vpnService.get(0, TimeUnit.NANOSECONDS).isLockdownEnabled();
}
/**
* Change the state of a given {@link Tunnel}, optionally applying a given {@link Config}.
*
@@ -359,35 +375,6 @@ public final class GoBackend implements Backend {
void alwaysOnTriggered();
}
// TODO: When we finally drop API 21 and move to API 24, delete this and replace with the ordinary CompletableFuture.
private static final class GhettoCompletableFuture<V> {
private final LinkedBlockingQueue<V> completion = new LinkedBlockingQueue<>(1);
private final FutureTask<V> result = new FutureTask<>(completion::peek);
public boolean complete(final V value) {
final boolean offered = completion.offer(value);
if (offered)
result.run();
return offered;
}
public V get() throws ExecutionException, InterruptedException {
return result.get();
}
public V get(final long timeout, final TimeUnit unit) throws ExecutionException, InterruptedException, TimeoutException {
return result.get(timeout, unit);
}
public boolean isDone() {
return !completion.isEmpty();
}
public GhettoCompletableFuture<V> newIncompleteFuture() {
return new GhettoCompletableFuture<>();
}
}
/**
* {@link android.net.VpnService} implementation for {@link GoBackend}
*/
@@ -417,7 +404,10 @@ public final class GoBackend implements Backend {
tunnel.onStateChange(State.DOWN);
}
}
vpnService = vpnService.newIncompleteFuture();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
vpnService = vpnService.newIncompleteFuture();
else
vpnService = new CompletableFuture<>();
super.onDestroy();
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -21,31 +21,7 @@ import androidx.annotation.Nullable;
*/
@NonNullForAll
public class Statistics {
// TODO: switch to Java Record class once R8 supports desugaring those.
public final class PeerStats {
public final long rxBytes, txBytes, latestHandshakeEpochMillis;
PeerStats(final long rxBytes, final long txBytes, final long latestHandshakeEpochMillis) {
this.rxBytes = rxBytes;
this.txBytes = txBytes;
this.latestHandshakeEpochMillis = latestHandshakeEpochMillis;
}
@Override public boolean equals(final Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
final PeerStats stats = (PeerStats) o;
return rxBytes == stats.rxBytes && txBytes == stats.txBytes && latestHandshakeEpochMillis == stats.latestHandshakeEpochMillis;
}
@Override public int hashCode() {
return Objects.hash(rxBytes, txBytes, latestHandshakeEpochMillis);
}
}
public record PeerStats(long rxBytes, long txBytes, long latestHandshakeEpochMillis) { }
private final Map<Key, PeerStats> stats = new HashMap<>();
private long lastTouched = SystemClock.elapsedRealtime();
@@ -85,7 +61,7 @@ public class Statistics {
*/
@Nullable
public PeerStats peer(final Key peer) {
return this.stats.get(peer);
return stats.get(peer);
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -109,6 +109,16 @@ public final class WgQuickBackend implements Backend {
return output.get(0);
}
@Override
public boolean isAlwaysOn() {
return false;
}
@Override
public boolean isLockdownEnabled() {
return false;
}
public void setMultipleTunnels(final boolean on) {
multipleTunnels = on;
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -46,8 +46,8 @@ public class RootShell {
final String packageName = context.getPackageName();
if (packageName.contains("'"))
throw new RuntimeException("Impossibly invalid package name contains a single quote");
preamble = String.format("export CALLING_PACKAGE=%s PATH=\"%s:$PATH\" TMPDIR='%s'; magisk --sqlite \"UPDATE policies SET notification=0, logging=0 WHERE package_name='%s'\" >/dev/null 2>&1; id -u\n",
packageName, localBinaryDir, localTemporaryDir, packageName);
preamble = String.format("export CALLING_PACKAGE='%s' PATH=\"%s:$PATH\" TMPDIR='%s'; magisk --sqlite \"UPDATE policies SET notification=0, logging=0 WHERE uid=%d\" >/dev/null 2>&1; id -u\n",
packageName, localBinaryDir, localTemporaryDir, android.os.Process.myUid());
}
private static boolean isExecutableInPath(final String name) {
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,6 +1,6 @@
/*
* Copyright © 2016 Southern Storm Software, Pty Ltd.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
+1 -1
View File
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
# Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
cmake_minimum_required(VERSION 3.4.1)
project("WireGuard")
+5 -5
View File
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
# Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
BUILDDIR ?= $(CURDIR)/build
DESTDIR ?= $(CURDIR)/out
@@ -20,12 +20,12 @@ export GOARCH := $(NDK_GO_ARCH_MAP_$(ANDROID_ARCH_NAME))
export GOOS := android
export CGO_ENABLED := 1
GO_VERSION := 1.20.3
GO_VERSION := 1.24.3
GO_PLATFORM := $(shell uname -s | tr '[:upper:]' '[:lower:]')-$(NDK_GO_ARCH_MAP_$(shell uname -m))
GO_TARBALL := go$(GO_VERSION).$(GO_PLATFORM).tar.gz
GO_HASH_darwin-amd64 := c1e1161d6d859deb576e6cfabeb40e3d042ceb1c6f444f617c3c9d76269c3565
GO_HASH_darwin-arm64 := 86b0ed0f2b2df50fa8036eea875d1cf2d76cefdacf247c44639a1464b7e36b95
GO_HASH_linux-amd64 := 979694c2c25c735755bf26f4f45e19e64e4811d661dd07b8c010f7a8e18adfca
GO_HASH_darwin-amd64 := 13e6fe3fcf65689d77d40e633de1e31c6febbdbcb846eb05fc2434ed2213e92b
GO_HASH_darwin-arm64 := 64a3fa22142f627e78fac3018ce3d4aeace68b743eff0afda8aae0411df5e4fb
GO_HASH_linux-amd64 := 3333f6ea53afa971e9078895eaa4ac7204a8c6b5c68c10e6bc9a33e8e391bdd8
default: $(DESTDIR)/libwg-go.so
+5 -5
View File
@@ -1,14 +1,14 @@
module golang.zx2c4.com/wireguard/android
go 1.20
go 1.23.1
require (
golang.org/x/sys v0.6.0
golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675
golang.org/x/sys v0.33.0
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb
)
require (
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/crypto v0.38.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
)
+14 -8
View File
@@ -1,10 +1,16 @@
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675 h1:/J/RVnr7ng4fWPRH3xa4WtBJ1Jp+Auu4YNLmGiPv5QU=
golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675/go.mod h1:whfbyDBt09xhCYQWtO2+3UVjlaq6/9hDZrjg2ZE6SyA=
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb h1:whnFRlWMcXI9d+ZbWg+4sHnLp52d5yiIPUxMBSt4X9A=
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb/go.mod h1:rpwXGsirqLqN2L0JDJQlwOboGHmptD5ZD6T2VmcqhTw=
gvisor.dev/gvisor v0.0.0-20250503011706-39ed1f5ac29c h1:m/r7OM+Y2Ty1sgBQ7Qb27VgIMBW8ZZhT4gLnUyDIhzI=
gvisor.dev/gvisor v0.0.0-20250503011706-39ed1f5ac29c/go.mod h1:3r5CMtNQMKIvBlrmM9xWUNamjKBYPOWyXOjmg5Kts3g=
+1 -1
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD
*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
*
*/
+1 -1
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD
*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
*
*/
+4 -19
View File
@@ -2,10 +2,6 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import com.android.build.gradle.tasks.GenerateLocaleConfigTask
// Grotesque workaround for https://issuetracker.google.com/issues/279780940
System.setProperty("com.android.tools.r8.disableApiModeling", "1")
val pkg: String = providers.gradleProperty("wireguardPackageName").get()
@@ -16,7 +12,7 @@ plugins {
}
android {
compileSdk = 33
compileSdk = 36
buildFeatures {
buildConfig = true
dataBinding = true
@@ -25,8 +21,8 @@ android {
namespace = pkg
defaultConfig {
applicationId = pkg
minSdk = 21
targetSdk = 33
minSdk = 24
targetSdk = 36
versionCode = providers.gradleProperty("wireguardVersionCode").get().toInt()
versionName = providers.gradleProperty("wireguardVersionName").get()
buildConfigField("int", "MIN_SDK_VERSION", minSdk.toString())
@@ -93,16 +89,5 @@ tasks.withType<JavaCompile>().configureEach {
}
tasks.withType<KotlinCompile>().configureEach {
compilerOptions.jvmTarget.set(JvmTarget.JVM_17)
compilerOptions.jvmTarget = JvmTarget.JVM_17
}
// Grotesque workaround for https://issuetracker.google.com/issues/281825213
tasks.withType<GenerateLocaleConfigTask>().configureEach {
doLast {
localeConfig.asFileTree.files.forEach {
val lines = it.readLines()
val newLines = lines.subList(0, 2) + lines.subList(2, lines.size - 1).sorted() + lines.last()
it.writeText(newLines.joinToString(separator = "\n"))
}
}
}
+4 -1
View File
@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
~ SPDX-License-Identifier: Apache-2.0
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
+7 -1
View File
@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
~ SPDX-License-Identifier: Apache-2.0
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="internalOnly">
@@ -7,6 +10,9 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission
android:name="android.permission.SYSTEM_ALERT_WINDOW"
android:minSdkVersion="34" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android
@@ -1,15 +1,18 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android
import android.app.PendingIntent
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.Icon
import android.net.Uri
import android.os.Build
import android.os.IBinder
import android.provider.Settings
import android.service.quicksettings.Tile
import android.service.quicksettings.TileService
import android.util.Log
@@ -29,7 +32,6 @@ import kotlinx.coroutines.launch
* system framework as necessary to update the appearance of the tile in the system UI, and to
* forward click events to the application.
*/
@RequiresApi(Build.VERSION_CODES.N)
class QuickTileService : TileService() {
private val onStateChangedCallback = OnStateChangedCallback()
private val onTunnelChangedCallback = OnTunnelChangedCallback()
@@ -49,22 +51,50 @@ class QuickTileService : TileService() {
}
override fun onClick() {
when (val tunnel = tunnel) {
null -> {
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivityAndCollapse(intent)
applicationScope.launch {
if (tunnel == null) {
Application.getTunnelManager().getTunnels()
updateTile()
}
else -> {
unlockAndRun {
applicationScope.launch {
try {
tunnel.setStateAsync(Tunnel.State.TOGGLE)
updateTile()
} catch (_: Throwable) {
val toggleIntent = Intent(this@QuickTileService, TunnelToggleActivity::class.java)
toggleIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(toggleIntent)
when (val tunnel = tunnel) {
null -> {
Log.d(TAG, "No tunnel set, so launching main activity")
val intent = Intent(this@QuickTileService, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
startActivityAndCollapse(PendingIntent.getActivity(this@QuickTileService, 0, intent, PendingIntent.FLAG_IMMUTABLE))
} else {
@Suppress("DEPRECATION")
startActivityAndCollapse(intent)
}
}
else -> {
unlockAndRun {
applicationScope.launch {
try {
tunnel.setStateAsync(Tunnel.State.TOGGLE)
updateTile()
} catch (e: Throwable) {
Log.d(TAG, "Failed to set state, so falling back", e)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && !Settings.canDrawOverlays(this@QuickTileService)) {
Log.d(TAG, "Need overlay permissions")
val permissionIntent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:$packageName"))
permissionIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivityAndCollapse(
PendingIntent.getActivity(
this@QuickTileService,
0,
permissionIntent,
PendingIntent.FLAG_IMMUTABLE
)
)
return@launch
}
val toggleIntent = Intent(this@QuickTileService, TunnelToggleActivity::class.java)
toggleIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(toggleIntent)
}
}
}
}
@@ -82,13 +112,13 @@ class QuickTileService : TileService() {
val icon = SlashDrawable(resources.getDrawable(R.drawable.ic_tile, Application.get().theme))
icon.setAnimationEnabled(false) /* Unfortunately we can't have animations, since Icons are marshaled. */
icon.setSlashed(false)
var b = Bitmap.createBitmap(icon.intrinsicWidth, icon.intrinsicHeight, Bitmap.Config.ARGB_8888) ?: return
var b = Bitmap.createBitmap(icon.intrinsicWidth, icon.intrinsicHeight, Bitmap.Config.ARGB_8888)
var c = Canvas(b)
icon.setBounds(0, 0, c.width, c.height)
icon.draw(c)
iconOn = Icon.createWithBitmap(b)
icon.setSlashed(true)
b = Bitmap.createBitmap(icon.intrinsicWidth, icon.intrinsicHeight, Bitmap.Config.ARGB_8888) ?: return
b = Bitmap.createBitmap(icon.intrinsicWidth, icon.intrinsicHeight, Bitmap.Config.ARGB_8888)
c = Canvas(b)
icon.setBounds(0, 0, c.width, c.height)
icon.draw(c)
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -183,7 +183,7 @@ class LogViewerActivity : AppCompatActivity() {
return
Snackbar.make(
findViewById(android.R.id.content),
if (exception == null) getString(R.string.log_export_success, outputFile?.fileName)
if (exception == null) getString(R.string.log_export_success, outputFile.fileName)
else getString(R.string.log_export_error, ErrorMessages[exception]),
if (exception == null) Snackbar.LENGTH_SHORT else Snackbar.LENGTH_LONG
)
@@ -223,7 +223,7 @@ class LogViewerActivity : AppCompatActivity() {
} else {
if (bufferedLogLines.isNotEmpty()) {
bufferedLogLines.last().msg += "\n$line"
} else if (!logLines.isEmpty) {
} else if (!logLines.isEmpty()) {
logLines[logLines.size() - 1].msg += "\n$line"
priorModified = true
}
@@ -353,7 +353,7 @@ class LogViewerActivity : AppCompatActivity() {
override fun query(uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor? =
logForUri(uri)?.let {
val m = MatrixCursor(arrayOf(android.provider.OpenableColumns.DISPLAY_NAME, android.provider.OpenableColumns.SIZE), 1)
m.addRow(arrayOf("wireguard-log.txt", it.size.toLong()))
m.addRow(arrayOf<Any>("wireguard-log.txt", it.size.toLong()))
m
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
@@ -80,7 +80,7 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener
R.id.menu_action_edit -> {
supportFragmentManager.commit {
replace(R.id.detail_container, TunnelEditorFragment())
replace(if (isTwoPaneLayout) R.id.detail_container else R.id.list_detail_container, TunnelEditorFragment())
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
addToBackStack(null)
}
@@ -119,7 +119,7 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener
} else if (backStackEntries == 0) {
// Create and show a new detail fragment.
fragmentManager.commit {
add(R.id.detail_container, TunnelDetailFragment())
add(if (isTwoPaneLayout) R.id.detail_container else R.id.list_detail_container, TunnelDetailFragment())
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
addToBackStack(null)
}
@@ -1,15 +1,16 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
import android.content.ComponentName
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.service.quicksettings.TileService
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.commit
import androidx.lifecycle.lifecycleScope
@@ -47,6 +48,15 @@ class SettingsActivity : AppCompatActivity() {
}
class SettingsFragment : PreferenceFragmentCompat() {
// Since this is pretty much abandoned by androidx, it never got updated for proper EdgeToEdge support,
// which is enabled everywhere for API 35. So handle the insets manually here.
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val view = super.onCreateView(inflater, container, savedInstanceState)
view.fitsSystemWindows = true
return view
}
override fun onCreatePreferences(savedInstanceState: Bundle?, key: String?) {
preferenceManager.preferenceDataStore = PreferencesPreferenceDataStore(lifecycleScope, Application.getPreferencesDataStore())
addPreferencesFromResource(R.xml.preferences)
@@ -62,10 +72,6 @@ class SettingsActivity : AppCompatActivity() {
darkTheme?.parent?.removePreference(darkTheme)
--preferenceScreen.initialExpandedChildrenCount
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
val remoteApps = preferenceManager.findPreference<Preference>("allow_remote_control_intents")
remoteApps?.parent?.removePreference(remoteApps)
}
if (AdminKnobs.disableConfigExport) {
val zipExporter = preferenceManager.findPreference<Preference>("zip_exporter")
zipExporter?.parent?.removePreference(zipExporter)
@@ -1,12 +1,11 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
import android.os.Bundle
import androidx.fragment.app.commit
import com.wireguard.android.fragment.TunnelEditorFragment
import com.wireguard.android.R
import com.wireguard.android.model.ObservableTunnel
/**
@@ -15,11 +14,7 @@ import com.wireguard.android.model.ObservableTunnel
class TunnelCreatorActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (supportFragmentManager.findFragmentById(android.R.id.content) == null) {
supportFragmentManager.commit {
add(android.R.id.content, TunnelEditorFragment())
}
}
setContentView(R.layout.tunnel_creator_activity)
}
override fun onSelectedTunnelChanged(oldTunnel: ObservableTunnel?, newTunnel: ObservableTunnel?): Boolean {
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
@@ -22,7 +22,6 @@ import com.wireguard.android.backend.Tunnel
import com.wireguard.android.util.ErrorMessages
import kotlinx.coroutines.launch
@RequiresApi(Build.VERSION_CODES.N)
class TunnelToggleActivity : AppCompatActivity() {
private val permissionActivityResultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { toggleTunnelWithPermissionsResult() }
@@ -50,10 +49,14 @@ class TunnelToggleActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
if (Application.getBackend() is GoBackend) {
val intent = GoBackend.VpnService.prepare(this@TunnelToggleActivity)
if (intent != null) {
permissionActivityResultLauncher.launch(intent)
return@launch
try {
val intent = GoBackend.VpnService.prepare(this@TunnelToggleActivity)
if (intent != null) {
permissionActivityResultLauncher.launch(intent)
return@launch
}
} catch (e: Exception) {
Toast.makeText(this@TunnelToggleActivity, ErrorMessages[e], Toast.LENGTH_LONG).show()
}
}
toggleTunnelWithPermissionsResult()
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -57,8 +57,8 @@ import kotlinx.coroutines.withContext
import java.io.File
class TvMainActivity : AppCompatActivity() {
private val tunnelFileImportResultLauncher = registerForActivityResult(object : ActivityResultContracts.GetContent() {
override fun createIntent(context: Context, input: String): Intent {
private val tunnelFileImportResultLauncher = registerForActivityResult(object : ActivityResultContracts.OpenDocument() {
override fun createIntent(context: Context, input: Array<String>): Intent {
val intent = super.createIntent(context, input)
/* AndroidTV now comes with stubs that do nothing but display a Toast less helpful than
@@ -209,12 +209,15 @@ class TvMainActivity : AppCompatActivity() {
}
} else {
try {
tunnelFileImportResultLauncher.launch("*/*")
tunnelFileImportResultLauncher.launch(arrayOf("*/*"))
} catch (_: Throwable) {
MaterialAlertDialogBuilder(binding.root.context).setMessage(R.string.tv_no_file_picker).setCancelable(false)
.setPositiveButton(android.R.string.ok) { _, _ ->
try {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://webstoreredirect")))
startActivity(Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse("https://play.google.com/store/apps/details?id=com.cxinventor.file.explorer")
setPackage("com.android.vending")
})
} catch (_: Throwable) {
}
}.show()
@@ -263,31 +266,14 @@ class TvMainActivity : AppCompatActivity() {
private suspend fun makeStorageRoots(): Collection<KeyedFile> = withContext(Dispatchers.IO) {
cachedRoots?.let { return@withContext it }
val list = HashSet<KeyedFile>()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val storageManager: StorageManager = getSystemService() ?: return@withContext list
list.addAll(storageManager.storageVolumes.mapNotNull { volume ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
volume.directory?.let { KeyedFile(it, volume.getDescription(this@TvMainActivity)) }
} else {
KeyedFile((StorageVolume::class.java.getMethod("getPathFile").invoke(volume) as File), volume.getDescription(this@TvMainActivity))
}
})
} else {
@Suppress("DEPRECATION")
list.add(KeyedFile(Environment.getExternalStorageDirectory()))
try {
File("/storage").listFiles()?.forEach {
if (!it.isDirectory) return@forEach
try {
if (Environment.isExternalStorageRemovable(it)) {
list.add(KeyedFile(it))
}
} catch (_: Throwable) {
}
}
} catch (_: Throwable) {
val storageManager: StorageManager = getSystemService() ?: return@withContext list
list.addAll(storageManager.storageVolumes.mapNotNull { volume ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
volume.directory?.let { KeyedFile(it, volume.getDescription(this@TvMainActivity)) }
} else {
KeyedFile((StorageVolume::class.java.getMethod("getPathFile").invoke(volume) as File), volume.getDescription(this@TvMainActivity))
}
}
})
cachedRoots = list
list
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.configStore
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.configStore
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
@@ -48,7 +48,7 @@ class AppListDialogFragment : DialogFragment() {
val packageInfos = getPackagesHoldingPermissions(pm, arrayOf(Manifest.permission.INTERNET))
packageInfos.forEach {
val packageName = it.packageName
val appInfo = it.applicationInfo
val appInfo = it.applicationInfo ?: return@forEach
val appData =
ApplicationData(appInfo.loadIcon(pm), appInfo.loadLabel(pm).toString(), packageName, currentlySelectedApps.contains(packageName))
applicationData.add(appData)
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.model
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.model
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.model
@@ -221,10 +221,9 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() {
manager.refreshTunnelStates()
return@launch
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || !UserKnobs.allowRemoteControlIntents.first())
if (!UserKnobs.allowRemoteControlIntents.first())
return@launch
val state: Tunnel.State
state = when (action) {
val state = when (action) {
"com.wireguard.android.action.SET_TUNNEL_UP" -> Tunnel.State.UP
"com.wireguard.android.action.SET_TUNNEL_DOWN" -> Tunnel.State.DOWN
else -> return@launch
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -15,6 +15,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.wireguard.android.R
import com.wireguard.android.updater.Updater
import com.wireguard.android.util.ErrorMessages
import androidx.core.net.toUri
class DonatePreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
override fun getSummary() = context.getString(R.string.donate_summary)
@@ -32,7 +33,7 @@ class DonatePreference(context: Context, attrs: AttributeSet?) : Preference(cont
}
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("https://www.wireguard.com/donations/")
intent.data = "https://www.wireguard.com/donations/".toUri()
try {
context.startActivity(intent)
} catch (e: Throwable) {
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright 2017 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.updater
@@ -50,11 +50,9 @@ object Updater {
private const val UPDATE_URL_FMT = "https://download.wireguard.com/android-client/%s"
private const val APK_NAME_PREFIX = BuildConfig.APPLICATION_ID + "-"
private const val APK_NAME_SUFFIX = ".apk"
private val CURRENT_VERSION = Version(BuildConfig.VERSION_NAME.removeSuffix("-debug"))
private val LATEST_FILE = if (BuildConfig.DEBUG) "latest-debug.sig" else "latest.sig"
private val RELEASE_PUBLIC_KEY_BASE64 =
if (BuildConfig.DEBUG) "RWTKFCNaLimMkuolGwAw12XT6sx+nnS7KE1wmhJ7YHXvAPedtPR/rofU"
else "RWTAzwGRYr3EC9px0Ia3fbttz8WcVN6wrOwWp2delz4el6SI8XmkKSMp"
private const val LATEST_FILE = "latest.sig"
private const val RELEASE_PUBLIC_KEY_BASE64 = "RWTAzwGRYr3EC9px0Ia3fbttz8WcVN6wrOwWp2delz4el6SI8XmkKSMp"
private val CURRENT_VERSION by lazy { Version(BuildConfig.VERSION_NAME) }
private val updaterScope = CoroutineScope(Job() + Dispatchers.IO)
@@ -266,7 +264,7 @@ object Updater {
throw IOException("Update could not be fetched: ${connection.responseCode}")
var downloadedByteLen: ULong = 0UL
val totalByteLen = (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) connection.contentLengthLong else connection.contentLength).toLong().toULong()
val totalByteLen = connection.contentLengthLong.toULong()
val fileBytes = ByteArray(1024 * 32 /* 32 KiB */)
val digest = MessageDigest.getInstance("SHA-256")
emitProgress(Progress.Downloading(downloadedByteLen, totalByteLen), true)
@@ -314,13 +312,18 @@ object Updater {
session.close()
}
private var updating = false
private suspend fun downloadAndUpdateWrapErrors() {
if (updating)
return
updating = true
try {
downloadAndUpdate()
} catch (e: Throwable) {
Log.e(TAG, "Update failure", e)
emitProgress(Progress.Failure(e))
}
updating = false
}
private class InstallReceiver : BroadcastReceiver() {
@@ -365,25 +368,39 @@ object Updater {
}
fun monitorForUpdates() {
if (BuildConfig.DEBUG)
return
val context = Application.get()
if (installerIsGooglePlay(context))
return
if (!if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
if (BuildConfig.BUILD_TYPE == "googleplay") {
if (installer(context).isNotEmpty()) {
applicationScope.launch {
emitProgress(Progress.Corrupt(null))
}
}
return
}
if (if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
@Suppress("DEPRECATION")
context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)
} else {
context.packageManager.getPackageInfo(context.packageName, PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS.toLong()))
}.requestedPermissions.contains(Manifest.permission.REQUEST_INSTALL_PACKAGES)
}.requestedPermissions?.contains(Manifest.permission.REQUEST_INSTALL_PACKAGES) != true
) {
updaterScope.launch {
val update = try {
checkForUpdates()
} catch (_: Throwable) {
null
if (installer(context).isNotEmpty()) {
updaterScope.launch {
val update = try {
checkForUpdates()
} catch (_: Throwable) {
null
}
emitProgress(Progress.Corrupt(update?.fileName))
}
emitProgress(Progress.Corrupt(update?.fileName))
}
return
}
@@ -440,4 +457,4 @@ object Updater {
context.startActivity(start)
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,11 +1,12 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.util
import android.content.ClipData
import android.content.ClipboardManager
import android.os.Build
import android.view.View
import android.widget.TextView
import androidx.core.content.getSystemService
@@ -29,6 +30,8 @@ object ClipboardUtils {
}
val service = view.context.getSystemService<ClipboardManager>() ?: return
service.setPrimaryClip(ClipData.newPlainText(data.second, data.first))
Snackbar.make(view, view.context.getString(R.string.copied_to_clipboard, data.second), Snackbar.LENGTH_LONG).show()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
Snackbar.make(view, view.context.getString(R.string.copied_to_clipboard, data.second), Snackbar.LENGTH_LONG).show()
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.util
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.util
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -29,7 +29,6 @@ class QrCodeFromFileScanner(
private val contentResolver: ContentResolver,
private val reader: Reader,
) {
private fun scanBitmapForResult(source: Bitmap): Result {
val width = source.width
val height = source.height
@@ -40,55 +39,28 @@ class QrCodeFromFileScanner(
return reader.decode(bBitmap, mapOf(DecodeHintType.TRY_HARDER to true))
}
private fun downscaleBitmap(source: Bitmap, scaledSize: Int): Bitmap {
val originalWidth = source.width
val originalHeight = source.height
var newWidth = -1
var newHeight = -1
val multFactor: Float
when {
originalHeight > originalWidth -> {
newHeight = scaledSize
multFactor = originalWidth.toFloat() / originalHeight.toFloat()
newWidth = (newHeight * multFactor).toInt()
}
originalWidth > originalHeight -> {
newWidth = scaledSize
multFactor = originalHeight.toFloat() / originalWidth.toFloat()
newHeight = (newWidth * multFactor).toInt()
}
originalHeight == originalWidth -> {
newHeight = scaledSize
newWidth = scaledSize
}
}
return Bitmap.createScaledBitmap(source, newWidth, newHeight, false)
}
private fun doScan(data: Uri): Result {
Log.d(TAG, "Starting to scan an image: $data")
contentResolver.openInputStream(data).use { inputStream ->
val originalBitmap = BitmapFactory.decodeStream(inputStream)
?: throw IllegalArgumentException("Can't decode stream to Bitmap")
return try {
scanBitmapForResult(originalBitmap).also {
Log.d(TAG, "Found result in original image")
var bitmap: Bitmap? = null
var firstException: Throwable? = null
for (i in arrayOf(1, 2, 4, 8, 16, 32, 64, 128)) {
try {
val options = BitmapFactory.Options()
options.inSampleSize = i
bitmap = BitmapFactory.decodeStream(inputStream, null, options)
?: throw IllegalArgumentException("Can't decode stream for bitmap")
return scanBitmapForResult(bitmap)
} catch (e: Throwable) {
bitmap?.recycle()
System.gc()
Log.e(TAG, "Original image scan at scale factor $i finished with error: $e")
if (firstException == null)
firstException = e
}
} catch (e: Exception) {
Log.e(TAG, "Original image scan finished with error: $e, will try downscaled image")
val scaleBitmap = downscaleBitmap(originalBitmap, 500)
scanBitmapForResult(originalBitmap).also { scaleBitmap.recycle() }
} finally {
originalBitmap.recycle()
}
throw Exception(firstException)
}
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -31,9 +31,6 @@ object QuantityFormatter {
fun formatEpochAgo(epochMillis: Long): String {
var span = (System.currentTimeMillis() - epochMillis) / 1000
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
return Application.get().applicationContext.getString(R.string.latest_handshake_ago, span.seconds.toString())
if (span <= 0L)
return RelativeDateTimeFormatter.getInstance().format(RelativeDateTimeFormatter.Direction.PLAIN, RelativeDateTimeFormatter.AbsoluteUnit.NOW)
val measureFormat = MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.viewmodel
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.viewmodel
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.viewmodel
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.widget
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.widget
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.widget

Some files were not shown because too many files have changed in this diff Show More