Hopefully will fix, "Only the original thread that creted a view
hierarchy can touch its views."
Reported-by: Damir <2k1dmg@gmail.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
These changes can happen at the wrong time, so we need to be able to
walk them back. Fixes:
Exception java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at androidx.fragment.app.FragmentManager.checkStateLoss (FragmentManager.java:1610)
at androidx.fragment.app.FragmentManager.enqueueAction (FragmentManager.java:1650)
at androidx.fragment.app.BackStackRecord.commitInternal (BackStackRecord.java:341)
at androidx.fragment.app.BackStackRecord.commit (BackStackRecord.java:306)
at androidx.fragment.app.FragmentManagerKt.commit$default (FragmentManager.kt:35)
at com.wireguard.android.activity.MainActivity.onSelectedTunnelChanged (MainActivity.kt:113)
at com.wireguard.android.activity.BaseActivity.setSelectedTunnel (BaseActivity.kt:25)
at com.wireguard.android.activity.BaseActivity$onCreate$1.invokeSuspend (BaseActivity.kt:44)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33)
at kotlinx.coroutines.internal.DispatchedContinuation.resumeUndispatchedWith (DispatchedContinuation.java:256)
at kotlinx.coroutines.DispatchedTaskKt.resume (DispatchedTask.kt:177)
at kotlinx.coroutines.CancellableContinuationImpl.parentCancelled$kotlinx_coroutines_core (CancellableContinuationImpl.kt:190)
at kotlinx.coroutines.DispatchedTaskKt.resumeUnconfined (DispatchedTask.kt:190)
at kotlinx.coroutines.DispatchedTaskKt.dispatch (DispatchedTask.kt:161)
at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume (CancellableContinuationImpl.kt:397)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl (CancellableContinuationImpl.kt:431)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default (CancellableContinuationImpl.kt:420)
at kotlinx.coroutines.CancellableContinuationImpl.resumeWith (CancellableContinuationImpl.kt:328)
at kotlinx.coroutines.ResumeAwaitOnCompletion.invoke (JobSupport.kt:1413)
at kotlinx.coroutines.JobSupport.notifyHandlers (JobSupport.kt:368)
at kotlinx.coroutines.JobSupport.notifyCompletion (JobSupport.kt:362)
at kotlinx.coroutines.JobSupport.completeStateFinalization (JobSupport.kt:323)
at kotlinx.coroutines.JobSupport.finalizeFinishingState (JobSupport.kt:240)
at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath (JobSupport.kt:906)
at kotlinx.coroutines.JobSupport.tryMakeCompleting (JobSupport.kt:863)
at kotlinx.coroutines.JobSupport.makeCompleting$kotlinx_coroutines_core (JobSupport.kt:806)
at kotlinx.coroutines.CompletableDeferredImpl.complete (CompletableDeferredImpl.java:92)
at com.wireguard.android.model.TunnelManager$onTunnelsLoaded$1.invokeSuspend (TunnelManager.kt:120)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:106)
at android.os.Handler.handleCallback (Handler.java:938)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:237)
at android.app.ActivityThread.main (ActivityThread.java:8163)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:656)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:967)
Exception java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at androidx.fragment.app.FragmentManager.checkStateLoss (FragmentManager.java:1610)
at androidx.fragment.app.FragmentManager.enqueueAction (FragmentManager.java:1650)
at androidx.fragment.app.BackStackRecord.commitInternal (BackStackRecord.java:341)
at androidx.fragment.app.BackStackRecord.commit (BackStackRecord.java:306)
at androidx.fragment.app.FragmentManagerKt.commit$default (FragmentManager.kt:35)
at com.wireguard.android.activity.MainActivity.onSelectedTunnelChanged (MainActivity.kt:113)
at com.wireguard.android.activity.BaseActivity.setSelectedTunnel (BaseActivity.kt:25)
at com.wireguard.android.activity.BaseActivity$onCreate$1.invokeSuspend (BaseActivity.kt:44)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33)
at kotlinx.coroutines.internal.DispatchedContinuation.resumeUndispatchedWith (DispatchedContinuation.java:256)
at kotlinx.coroutines.DispatchedTaskKt.resume (DispatchedTask.kt:177)
at kotlinx.coroutines.CancellableContinuationImpl.parentCancelled$kotlinx_coroutines_core (CancellableContinuationImpl.kt:190)
at kotlinx.coroutines.DispatchedTaskKt.resumeUnconfined (DispatchedTask.kt:190)
at kotlinx.coroutines.DispatchedTaskKt.dispatch (DispatchedTask.kt:161)
at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume (CancellableContinuationImpl.kt:397)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl (CancellableContinuationImpl.kt:431)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default (CancellableContinuationImpl.kt:420)
at kotlinx.coroutines.CancellableContinuationImpl.resumeWith (CancellableContinuationImpl.kt:328)
at kotlinx.coroutines.ResumeAwaitOnCompletion.invoke (JobSupport.kt:1413)
at kotlinx.coroutines.JobSupport.notifyHandlers (JobSupport.kt:368)
at kotlinx.coroutines.JobSupport.notifyCompletion (JobSupport.kt:362)
at kotlinx.coroutines.JobSupport.completeStateFinalization (JobSupport.kt:323)
at kotlinx.coroutines.JobSupport.finalizeFinishingState (JobSupport.kt:240)
at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath (JobSupport.kt:906)
at kotlinx.coroutines.JobSupport.tryMakeCompleting (JobSupport.kt:863)
at kotlinx.coroutines.JobSupport.makeCompleting$kotlinx_coroutines_core (JobSupport.kt:806)
at kotlinx.coroutines.CompletableDeferredImpl.complete (CompletableDeferredImpl.java:92)
at com.wireguard.android.model.TunnelManager$onTunnelsLoaded$1.invokeSuspend (TunnelManager.kt:120)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:106)
at android.os.Handler.handleCallback (Handler.java:938)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loopOnce (Looper.java:210)
at android.os.Looper.loop (Looper.java:299)
at android.app.ActivityThread.main (ActivityThread.java:8302)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:556)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1037)
Exception java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at androidx.fragment.app.FragmentManager.checkStateLoss (FragmentManager.java:1610)
at androidx.fragment.app.FragmentManager.ensureExecReady (FragmentManager.java:1711)
at androidx.fragment.app.FragmentManager.execPendingActions (FragmentManager.java:1754)
at androidx.fragment.app.FragmentManager.popBackStackImmediate (FragmentManager.java:854)
at androidx.fragment.app.FragmentManager.popBackStackImmediate (FragmentManager.java:778)
at com.wireguard.android.activity.MainActivity.onSelectedTunnelChanged (MainActivity.kt:110)
at com.wireguard.android.activity.BaseActivity.setSelectedTunnel (BaseActivity.kt:25)
at com.wireguard.android.activity.BaseActivity$onCreate$1.invokeSuspend (BaseActivity.kt:44)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:106)
at kotlinx.coroutines.EventLoop.processUnconfinedEvent (EventLoop.common.kt:69)
at kotlinx.coroutines.DispatchedTaskKt.runUnconfinedEventLoop (DispatchedTask.kt:204)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith (DispatchedContinuation.kt:282)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable (Cancellable.kt:30)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default (Cancellable.kt:25)
at kotlinx.coroutines.CoroutineStart.invoke (CoroutineStart.java:110)
at kotlinx.coroutines.AbstractCoroutine.start (AbstractCoroutine.kt:126)
at kotlinx.coroutines.BuildersKt.launch$default (Builders.kt)
at com.wireguard.android.model.TunnelManager.onTunnelsLoaded (TunnelManager.java:114)
at com.wireguard.android.model.TunnelManager.access$onTunnelsLoaded (TunnelManager.java:40)
at com.wireguard.android.model.TunnelManager$onCreate$1.invokeSuspend (TunnelManager.kt:104)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:106)
at android.os.Handler.handleCallback (Handler.java:942)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loopOnce (Looper.java:226)
at android.os.Looper.loop (Looper.java:313)
at android.app.ActivityThread.main (ActivityThread.java:8757)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067)
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
The primary color changes in night theme, and since there's no proper
mode for the status icons on those APIs, it looks bad.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Since version 1.1.0, setDefaultNightMode now takes care of that. Also,
set the initial mode in a blocking fashion to prevent flashing white.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This change lets us use the same build for F-Droid, Play Store, self
builds, and elsewhere, which makes everything more easily publicly
verifiable, since the build system is reproducible. That means that all
APKs will have the same code and be completely interchangeable, no
matter where they come from.
It does this by removing the build-time branch for special Play Store
builds, and replacing it with a simple runtime check using the
PackageManager APIs that return the name of the installer. If the app is
installed by "com.android.vending", then it's a Play Store install.
It's possible to test this with:
$ pm install -i com.android.vending path/to/package.apk
And it appears to work well.
One potential concern is that it's unclear whether the Play Store
reviewers install the app using utilities that set com.android.vending
like this. If not, that might be a problem. However, it looks like
various banking apps also use the installer package name check in the
same way, and refuse to start if it's not right. That suggests that it
would be impossible for Play Store reviewers to even review those
banking apps if they did not set com.android.vending properly.
Out of an abundance of caution, though, and in order to avoid a Play
Store suspension that's harder to appeal, I sent a support request
today (which just managed to fit exactly in the 1000 character limit):
Hi,
My app pays special attention to Google Play Store guidelines. For that
reason, there is some code in the app that looks like this:
if (BuildConfig.IS_GOOGLE_PLAY)
...
else
...
This means that I compile two versions of my app, one for Google Play,
and another for other app stores. This has worked well for many years
and it satisfies Google's policy requirements.
However, compiling two versions of my app is a bit of a pain. Instead, I
would like to do this check at runtime, with code like this:
if (pm.getInstallSourceInfo(package).installingPackageName == "com.android.vending")
...
else
...
I have tested that this code works well, and I've installed my app with:
$ pm install -i com.android.vending ui-release.apk
This works and successfully satisfies the policy requirements.
My question is how this works during the review process. Are reviewed
apps installed with the necessary -i com.android.vending switch to make
this work?
Thanks.
They responded fairly quickly:
Hi Jason,
Thanks for contacting the Google Play team.
Unfortunately I'm not able to comment on your planned implementation. If
you think your app is in compliance, please submit your app for review.
You may want to review the Developer Program Policies for additional
policy guidance.
We recommend reviewing the details listed in this blog post and update
your app accordingly to comply with the changes.
Thanks for your understanding and continued support.
Regards,
Mia
Google Play Developer Support
So I'll interpret that as a, "if you think it's okay, submit it and see,
and then we'll let you know." So here we go. Hopefully if it is
rejected, the update will only be blocked, and I'll just revert this
commit and resubmit.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
All of the parcelers have their own type prefix. So we have to actually
use the legit methods. This is a bit annoying, as there's no fully
compatible way across all API versions, so we have to branch.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Exception java.lang.IllegalStateException:
at androidx.fragment.app.FragmentStore.addFragment (FragmentStore.java:92)
at androidx.fragment.app.FragmentManager.addFragment (FragmentManager.java:1481)
at androidx.fragment.app.BackStackRecord.executeOps (BackStackRecord.java:387)
at androidx.fragment.app.FragmentManager.executeOps (FragmentManager.java:1965)
at androidx.fragment.app.FragmentManager.executeOpsTogether (FragmentManager.java:1873)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute (FragmentManager.java:1823)
at androidx.fragment.app.FragmentManager.execPendingActions (FragmentManager.java:1760)
at androidx.fragment.app.FragmentManager$5.run (FragmentManager.java:547)
at android.os.Handler.handleCallback (Handler.java:938)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:268)
at android.app.ActivityThread.main (ActivityThread.java:8101)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:627)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:997)
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Exception java.lang.IllegalStateException:
at androidx.fragment.app.Fragment.requireContext (Fragment.java:967)
at com.wireguard.android.fragment.TunnelListFragment$tunnelFileImportResultLauncher$1$1.invokeSuspend (TunnelListFragment.kt:64)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:104)
at android.os.Handler.handleCallback (Handler.java:761)
at android.os.Handler.dispatchMessage (Handler.java:98)
at android.os.Looper.loop (Looper.java:156)
at android.app.ActivityThread.main (ActivityThread.java:6617)
at java.lang.reflect.Method.invoke
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:942)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:832)
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Harsh - feel free to replace this commit with something better. I'm sure
it's the most terrible way to do it.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>