This has several problems: 1) it blocks the main thread; 2) it doesn't
distinguish between a permanent error and a transient one; 3) the 10
seconds is hard coded; 4) there's no way for the user to cancel it.
We'll have to improve this.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This will be rendered on an even smaller scale on devices, but
400dp x 400dp was simply too big and could cause performance issues.
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
Some folks use chromebooks, which don't have rear cameras.
Reported-by: Jay Tuley <jay.tuley@ekonbenefits.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
If we're horizontally scrolling, it makes sense to fill rows before
columns. But if it all fits in one page and we don't need to scroll
horizontally, it looks ridiculous. So, in this case, rearrange the tiles
so that it appears to fill columns before rows. But we don't want things
suddenly jumping around, so actually, keep the same ordering as
rows-before-columns, but add invisible spaces after certain items, so
that the fill area makes it look as though it's columns-before-rows.
This winds up being much more visually pleasing.
We do this by figuring out this kind of transformation:
If we convert this matrix:
0 3 6
1 4 _
2 5 _
To this one:
0 2 4 6
1 3 5 _
_ _ _ _
For a given index, how many spaces are under it? This changes depending
on how many total are in a grid. Going from 3x3 to 4x3, for example, we
have:
count == 12, index =
count == 11, index = 10
count == 10, index = 7,9
count == 9, index = 4,6,8
count == 8, index = 1,3,5,7
count == 7, index = 1,3,5,6!
count == 6, index = 1,3,4!,5!
count == 5, index = 1,2!,3!,4!
count == 4, index = 0!,1!,2!,3!
count == 3, index = 0!,1!,2!
count == 2, index = 0!,1!
count == 1, index = 0!
count == 0, index =
The '!' means two blanks below, no '!' means one blank below, and no
mention means no blanks below.
This commit adds code to compute such a table on the fly.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Fragment scopes get cancelled when the fragment goes away, but we don't
actually want to cancel an in-flight transition in that case. Also,
before when the fragment would cancel, there'd be an exception, and the
exception handler would call Fragment::getString, which in turn called
requireContext, which caused an exception. Work around this by using the
`activity ?: Application.get()` idiom to always have a context for
strings and toasts.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This is kind of ridiculous, since the items own state should clearly be
queryable, but it doesn't appear to be the case here, so just shuffle it
around into kotlin and back.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
java.lang.IllegalStateException:
at android.app.ContextImpl.startServiceCommon (ContextImpl.java:1720)
at android.app.ContextImpl.startService (ContextImpl.java:1675)
at android.content.ContextWrapper.startService (ContextWrapper.java:669)
at com.wireguard.android.backend.GoBackend.startVpnService (GoBackend.java:4)
at com.wireguard.android.backend.GoBackend.setStateInternal (GoBackend.java:4)
at com.wireguard.android.backend.GoBackend.setState (GoBackend.java:2)
at com.wireguard.android.model.TunnelManager$setTunnelState$2$1.invokeSuspend (TunnelManager.java:6)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (BaseContinuationImpl.java:2)
at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.java:2)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely (CoroutineScheduler.java)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask (CoroutineScheduler.java:7)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker (CoroutineScheduler.java:7)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run (CoroutineScheduler.java:7)
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
java.lang.IllegalStateException:
at androidx.fragment.app.Fragment.requireContext (Fragment.java:17)
at com.wireguard.android.fragment.BaseFragment$setTunnelStateWithPermissionsResult$1.invokeSuspend (BaseFragment.java:4)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (BaseContinuationImpl.java:2)
at kotlinx.coroutines.UndispatchedCoroutine.afterResume (UndispatchedCoroutine.java:19)
at kotlinx.coroutines.AbstractCoroutine.resumeWith (AbstractCoroutine.java:13)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (BaseContinuationImpl.java:2)
at kotlinx.coroutines.UndispatchedCoroutine.afterResume (UndispatchedCoroutine.java:19)
at kotlinx.coroutines.AbstractCoroutine.resumeWith (AbstractCoroutine.java:13)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (BaseContinuationImpl.java:2)
at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.java:2)
at android.os.Handler.handleCallback (Handler.java:790)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:164)
at android.app.ActivityThread.main (ActivityThread.java:7025)
at java.lang.reflect.Method.invoke (Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:441)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1408)
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
GlobalScope has numerous problems[1] that make it unfit for
use in most applications and making it behave correctly requires
an excessive amount of verbosity that's alleviated simply by using
any other scope. Since we run multiple operations in the context
of the application's lifecycle, introduce a new scope that is created
when our application is, and cancelled upon its termination.
While at it, make the scope default to Dispatchers.IO to reduce pressure
on the UI event loop. Tasks requiring access to the UI thread appropriately
switch context making the change completely safe.
1: https://medium.com/@elizarov/the-reason-to-avoid-globalscope-835337445abc
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
onSelectedTunnelChanged is already queueing us to Dispatchers.Main
(rather than Dispatchers.Main.immediate, which would crash, but why?),
so avoid the extra trip through the event loop by toggling the selected
tunnel right away.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
- Mark WRITE_EXTERNAL_STORAGE as unused above API 29 since we defer to Storage Access Framework on P and above
- Adds a <queries> tag to allow listing apps for exclusion/inclusion dialog
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>