aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorfelix <Felix.nuesse@t-online.de>2025-09-20 12:14:21 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2025-10-20 18:22:47 +0200
commit6727b078e75793d12fed266675f1564d763250ed (patch)
tree682cda853361e2e08cd7d46ed6617ab04185646c
parentbuild: set up and check in a baseline for Lint warnings (diff)
downloadwireguard-android-hs/build-upgrades.tar.xz
wireguard-android-hs/build-upgrades.zip
ui: remove use of SYSTEM_ALERT_WINDOW for QS tilehs/build-upgrades
Harsh: massage codestyle and commit message Signed-off-by: felix <Felix.nuesse@t-online.de> Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
-rw-r--r--ui/src/main/AndroidManifest.xml3
-rw-r--r--ui/src/main/java/com/wireguard/android/QuickTileService.kt41
-rw-r--r--ui/src/main/java/com/wireguard/android/activity/TunnelToggleActivity.kt37
-rw-r--r--ui/src/main/res/layout/loading_activity.xml44
-rw-r--r--ui/src/main/res/values/strings.xml2
-rw-r--r--ui/src/main/res/values/styles.xml4
6 files changed, 101 insertions, 30 deletions
diff --git a/ui/src/main/AndroidManifest.xml b/ui/src/main/AndroidManifest.xml
index 86c989b3..99bd23db 100644
--- a/ui/src/main/AndroidManifest.xml
+++ b/ui/src/main/AndroidManifest.xml
@@ -11,9 +11,6 @@
<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"
tools:ignore="ScopedStorage" />
diff --git a/ui/src/main/java/com/wireguard/android/QuickTileService.kt b/ui/src/main/java/com/wireguard/android/QuickTileService.kt
index a849c481..ee94b055 100644
--- a/ui/src/main/java/com/wireguard/android/QuickTileService.kt
+++ b/ui/src/main/java/com/wireguard/android/QuickTileService.kt
@@ -4,15 +4,14 @@
*/
package com.wireguard.android
+import android.annotation.SuppressLint
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
@@ -21,6 +20,7 @@ import androidx.databinding.Observable
import androidx.databinding.Observable.OnPropertyChangedCallback
import com.wireguard.android.activity.MainActivity
import com.wireguard.android.activity.TunnelToggleActivity
+import com.wireguard.android.activity.TunnelToggleActivity.Companion.SHOW_PROGRESS
import com.wireguard.android.backend.Tunnel
import com.wireguard.android.model.ObservableTunnel
import com.wireguard.android.util.applicationScope
@@ -52,9 +52,9 @@ class QuickTileService : TileService() {
override fun onClick() {
applicationScope.launch {
+ updateTile()
if (tunnel == null) {
Application.getTunnelManager().getTunnels()
- updateTile()
}
when (val tunnel = tunnel) {
null -> {
@@ -64,7 +64,7 @@ class QuickTileService : TileService() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
startActivityAndCollapse(PendingIntent.getActivity(this@QuickTileService, 0, intent, PendingIntent.FLAG_IMMUTABLE))
} else {
- @Suppress("DEPRECATION")
+ @Suppress("DEPRECATION", "StartActivityAndCollapseDeprecated")
startActivityAndCollapse(intent)
}
}
@@ -76,24 +76,15 @@ class QuickTileService : TileService() {
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 intent = Intent(this@QuickTileService, TunnelToggleActivity::class.java)
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ intent.putExtra(SHOW_PROGRESS, true)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ startActivityAndCollapse(PendingIntent.getActivity(this@QuickTileService, 0, intent, PendingIntent.FLAG_IMMUTABLE))
+ } else {
+ @Suppress("DEPRECATION")
+ startActivity(intent)
}
- val toggleIntent = Intent(this@QuickTileService, TunnelToggleActivity::class.java)
- toggleIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- startActivity(toggleIntent)
}
}
}
@@ -149,7 +140,7 @@ class QuickTileService : TileService() {
isAdded = false
}
- private fun updateTile() {
+ private fun updateTile(isConnecting: Boolean = false) {
// Update the tunnel.
val newTunnel = Application.getTunnelManager().lastUsedTunnel
if (newTunnel != tunnel) {
@@ -164,6 +155,12 @@ class QuickTileService : TileService() {
null -> {
tile.label = getString(R.string.app_name)
tile.state = Tile.STATE_INACTIVE
+ if (isConnecting) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ tile.subtitle = getString(R.string.quick_settings_tile_connecting)
+ tile.state = Tile.STATE_ACTIVE
+ }
+ }
tile.icon = iconOff
}
else -> {
diff --git a/ui/src/main/java/com/wireguard/android/activity/TunnelToggleActivity.kt b/ui/src/main/java/com/wireguard/android/activity/TunnelToggleActivity.kt
index a0e9aa06..6eb877fa 100644
--- a/ui/src/main/java/com/wireguard/android/activity/TunnelToggleActivity.kt
+++ b/ui/src/main/java/com/wireguard/android/activity/TunnelToggleActivity.kt
@@ -5,13 +5,13 @@
package com.wireguard.android.activity
import android.content.ComponentName
-import android.os.Build
import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
import android.service.quicksettings.TileService
import android.util.Log
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
-import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.wireguard.android.Application
@@ -23,6 +23,9 @@ import com.wireguard.android.util.ErrorMessages
import kotlinx.coroutines.launch
class TunnelToggleActivity : AppCompatActivity() {
+
+ private var isVisible = false
+
private val permissionActivityResultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { toggleTunnelWithPermissionsResult() }
@@ -37,16 +40,23 @@ class TunnelToggleActivity : AppCompatActivity() {
val message = getString(R.string.toggle_error, error)
Log.e(TAG, message, e)
Toast.makeText(this@TunnelToggleActivity, message, Toast.LENGTH_LONG).show()
- finishAffinity()
+ exitActivity()
return@launch
}
TileService.requestListeningState(this@TunnelToggleActivity, ComponentName(this@TunnelToggleActivity, QuickTileService::class.java))
- finishAffinity()
+ exitActivity()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+
+ if (intent.getBooleanExtra(SHOW_PROGRESS, false)) {
+ isVisible = true
+ title = "" // Otherwise the app title will be shown above the spinner.
+ setContentView(R.layout.loading_activity)
+ }
+
lifecycleScope.launch {
if (Application.getBackend() is GoBackend) {
try {
@@ -61,9 +71,28 @@ class TunnelToggleActivity : AppCompatActivity() {
}
toggleTunnelWithPermissionsResult()
}
+ exitActivity()
+ }
+
+ private fun exitActivity() {
+ /*
+ We add this delay, so that the user gets the impression we are actually doing something.
+ This is to make the transition of the closing quick tile menu more palatable,
+ because startActivityAndCollapse() will immediately close that menu.
+ This can be jarring, so we show this placeholder spinner and close it after a second.
+ */
+
+ if (isVisible) {
+ Handler(Looper.getMainLooper()).postDelayed({
+ finishAffinity()
+ }, 1000L)
+ } else {
+ finishAffinity()
+ }
}
companion object {
private const val TAG = "WireGuard/TunnelToggleActivity"
+ const val SHOW_PROGRESS = "ShowLoadingbar"
}
}
diff --git a/ui/src/main/res/layout/loading_activity.xml b/ui/src/main/res/layout/loading_activity.xml
new file mode 100644
index 00000000..6c530f99
--- /dev/null
+++ b/ui/src/main/res/layout/loading_activity.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+
+ <com.google.android.material.card.MaterialCardView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checkable="true"
+ android:focusable="true"
+ app:contentPadding="32dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/textView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="24dp"
+ android:text="@string/preparing_tunnel" />
+
+ <ProgressBar
+ android:id="@+id/progressBar"
+ style="?android:attr/progressBarStyle"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ </LinearLayout>
+
+ </com.google.android.material.card.MaterialCardView>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>
diff --git a/ui/src/main/res/values/strings.xml b/ui/src/main/res/values/strings.xml
index 32e797e6..178f131e 100644
--- a/ui/src/main/res/values/strings.xml
+++ b/ui/src/main/res/values/strings.xml
@@ -260,4 +260,6 @@
<string name="biometric_prompt_private_key_title">Authenticate to view private key</string>
<string name="biometric_auth_error">Authentication failure</string>
<string name="biometric_auth_error_reason">Authentication failure: %s</string>
+ <string name="quick_settings_tile_connecting">Connecting…</string>
+ <string name="preparing_tunnel">Preparing tunnel…</string>
</resources>
diff --git a/ui/src/main/res/values/styles.xml b/ui/src/main/res/values/styles.xml
index 28e9fc2f..3b7bfdf6 100644
--- a/ui/src/main/res/values/styles.xml
+++ b/ui/src/main/res/values/styles.xml
@@ -37,9 +37,11 @@
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:background">@android:color/transparent</item>
<item name="colorPrimaryDark">@android:color/transparent</item>
- <item name="android:backgroundDimEnabled">true</item>
+ <item name="android:backgroundDimEnabled">false</item>
<item name="android:windowEnterAnimation">@android:anim/fade_in</item>
<item name="android:windowExitAnimation">@android:anim/fade_out</item>
+ <item name="android:windowIsFloating">true</item>
+ <item name="android:colorBackgroundCacheHint">@null</item>
</style>
<style name="TvTheme" parent="AppTheme">