aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ui/src/main/java/com/wireguard/android (follow)
Commit message (Collapse)AuthorAgeFilesLines
* QrCodeFromFileScanner: more efficiently downscale images and release memoryJason A. Donenfeld2025-05-311-44/+16
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* QrCodeFromFileScanner: catch OOM errorsJason A. Donenfeld2025-05-311-1/+1
| | | | | | | 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>
* QuickTileService: wait for tunnels to loadJason A. Donenfeld2025-05-281-0/+4
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* QuickTileService: handle onClick in applicationScopeJason A. Donenfeld2025-05-281-25/+38
| | | | | | This helps with the case where the TunnelManager is still loading. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* TvMainActivity: link to cx file explorerJason A. Donenfeld2025-05-231-1/+4
| | | | | | | | | | | | | | | | | | | 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>
* DonatePreferences: use toUri() extensionJason A. Donenfeld2025-05-211-1/+2
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* MainActivity: don't reuse id names across layoutsJason A. Donenfeld2025-05-191-2/+2
| | | | | | | This causes problems on foldables. Reported-by: Josh Dague <josh3736@gmail.com> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* global: update copyright noticesJason A. Donenfeld2025-05-1958-58/+58
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* TunnelCreatorActivity: use proper xml for layoutJason A. Donenfeld2025-05-191-15/+2
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* TunnelToggleActivity: suppress errors from prepare() in lockdown modeJason A. Donenfeld2025-05-161-4/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* ui: set fitsSystemWindows=true for EdgeToEdge on API 35+Jason A. Donenfeld2025-05-162-13/+9
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* TvMainActivity: use OpenDocument instead of GetContentJason A. Donenfeld2025-05-161-3/+3
| | | | | | This should make it possible to open files on Android TV 14. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* LogViewerActivity: cast array to Any type instead of using union inferenceJason A. Donenfeld2025-05-081-1/+1
| | | | | | | | | | 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>
* SettingsActivity: manually apply insets for api 35Jason A. Donenfeld2025-05-081-0/+24
| | | | | | | | 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>
* SettingsActivity: remove unused importsJason A. Donenfeld2025-05-081-2/+0
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* gradle: update kotlin to 2.1.20Jason A. Donenfeld2025-05-051-0/+1
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* gradle: target API 36Jason A. Donenfeld2025-05-052-3/+3
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* QuickTileService: require SYSTEM_ALERT_WINDOW to start background activityJason A. Donenfeld2023-10-181-1/+9
| | | | | | | | | 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>
* gradle: bump many depsJason A. Donenfeld2023-10-131-1/+1
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: only show a snackbar for Android 12 and lowerSlipkHunter2023-09-121-1/+4
| | | | | Signed-off-by: SlipkHunter <abrito025@gmail.com> Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
* ui: hide corrupted message if no installerJason A. Donenfeld2023-07-071-6/+8
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: remove unused elvis operatorsJason A. Donenfeld2023-07-061-2/+2
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: use api 34's startActivityAndCollapseJason A. Donenfeld2023-07-061-1/+7
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: add basic double update guardJason A. Donenfeld2023-05-261-0/+5
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: remove debug keysJason A. Donenfeld2023-05-261-6/+7
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: use modal corruption alert instead of snackbarJason A. Donenfeld2023-05-111-12/+21
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: use applicationScope helper when possibleJason A. Donenfeld2023-05-111-7/+8
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: cleanup quick tile and modernizeJason A. Donenfeld2023-05-111-44/+40
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: add shortcut for adding quick settings tileJason A. Donenfeld2023-05-103-1/+76
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: bifurcate only parts of release but nag about wrong contextJason A. Donenfeld2023-05-102-7/+51
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: use debug key in debug buildsJason A. Donenfeld2023-05-081-6/+8
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: only register contracts in constructorsJason A. Donenfeld2023-05-082-21/+21
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* gradle: restore play runtime detectionJason A. Donenfeld2023-05-083-22/+19
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: reformat all codeJason A. Donenfeld2023-05-0534-257/+320
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: collect logs from IO thread onlyJason A. Donenfeld2023-05-051-11/+15
| | | | | | | | | | | | | | | | | | | | | Otherwise the pop() from the producer might causes an OOB read in the consumer: Exception java.lang.ArrayIndexOutOfBoundsException: at androidx.collection.CircularArray.get (CircularArray.java) at com.wireguard.android.activity.LogViewerActivity.rawLogBytes (LogViewerActivity.java) at com.wireguard.android.activity.LogViewerActivity.onCreate$lambda$3 (LogViewerActivity.java:133) at android.view.View.performClick (View.java:6935) at android.view.View$PerformClick.run (View.java:26214) 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:7000) at java.lang.reflect.Method.invoke 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>
* gradle: remove runtime detection of play storeJason A. Donenfeld2023-05-044-30/+35
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: update cleanupsJason A. Donenfeld2023-05-031-79/+98
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: use .seconds instead of .toDurationJason A. Donenfeld2023-05-051-2/+2
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: handle update signaturesJason A. Donenfeld2023-05-018-15/+3114
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: display latest handshake timeJason A. Donenfeld2023-04-242-7/+63
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: LogViewerActivity: cleanup ret valJason A. Donenfeld2023-04-131-2/+1
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: further reduce log viewer memory usageJason A. Donenfeld2023-04-121-2/+1
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* tunnel: defer enabling strict mode until laterJason A. Donenfeld2023-04-111-4/+5
| | | | | | Startup code can be synchronous. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: always show visible localized error messagesJason A. Donenfeld2023-04-071-3/+3
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: set app list button text on main threadJason A. Donenfeld2023-04-071-1/+1
| | | | | | | | 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>
* ui: allow vetoing tunnel selection changesJason A. Donenfeld2023-04-053-6/+15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* ui: no need to manually recreate activities after night changeJason A. Donenfeld2023-04-055-42/+21
| | | | | | | 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>
* ui: distinguish play store installs at runtime for reproducible buildsJason A. Donenfeld2023-04-051-2/+15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* ui: always use MaterialAlertDialogBuilderJason A. Donenfeld2023-04-041-3/+5
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
* ui: force dark theme in TV modeJason A. Donenfeld2023-04-042-2/+19
| | | | Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>