feat(android): UI notification for reauth (#3621)

Fixes #3329

---------

Signed-off-by: Jason Elie Bou Kheir <5115126+jasonboukheir@users.noreply.github.com>
Signed-off-by: Jamil <jamilbk@users.noreply.github.com>
Co-authored-by: Jamil <jamilbk@users.noreply.github.com>
This commit is contained in:
Jason Elie Bou Kheir
2024-03-30 11:05:57 -07:00
committed by GitHub
parent 0c794a374f
commit b0bde8b0a7
3 changed files with 109 additions and 45 deletions

View File

@@ -6,6 +6,7 @@ import android.util.Log
import com.google.gson.Gson
import dev.firezone.android.tunnel.ConnlibSession
import dev.firezone.android.tunnel.TunnelService
import dev.firezone.android.tunnel.TunnelStatusNotification
import java.net.InetAddress
class NetworkMonitor(private val tunnelService: TunnelService) : ConnectivityManager.NetworkCallback() {
@@ -19,7 +20,7 @@ class NetworkMonitor(private val tunnelService: TunnelService) : ConnectivityMan
Log.d("NetworkMonitor", "OnLinkPropertiesChanged: $network: $linkProperties")
if (tunnelService.tunnelState != TunnelService.Companion.State.UP) {
tunnelService.tunnelState = TunnelService.Companion.State.UP
tunnelService.updateStatusNotification("Status: Connected")
tunnelService.updateStatusNotification(TunnelStatusNotification.Connected)
}
if (lastDns != linkProperties.dnsServers) {

View File

@@ -3,10 +3,6 @@ package dev.firezone.android.tunnel
import NetworkMonitor
import android.app.ActivityManager
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
@@ -20,16 +16,13 @@ import android.os.Build
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.lifecycle.MutableLiveData
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapter
import dagger.hilt.android.AndroidEntryPoint
import dev.firezone.android.R
import dev.firezone.android.core.data.Repository
import dev.firezone.android.core.presentation.MainActivity
import dev.firezone.android.tunnel.callback.ConnlibCallback
import dev.firezone.android.tunnel.model.Cidr
import dev.firezone.android.tunnel.model.Resource
@@ -143,7 +136,9 @@ class TunnelService : VpnService() {
repo.clearActorName()
shutdown()
if (startedByUser) {
updateStatusNotification(TunnelStatusNotification.SignedOut)
}
return true
}
@@ -232,7 +227,7 @@ class TunnelService : VpnService() {
if (!token.isNullOrBlank()) {
tunnelState = State.CONNECTING
updateStatusNotification("Status: Connecting...")
updateStatusNotification(TunnelStatusNotification.Connecting)
System.loadLibrary("connlib")
connlibSessionPtr =
@@ -307,15 +302,6 @@ class TunnelService : VpnService() {
return deviceId
}
private fun configIntent(): PendingIntent? {
return PendingIntent.getActivity(
this,
0,
Intent(this, MainActivity::class.java),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
private fun getLogDir(): String {
// Create log directory if it doesn't exist
val logDir = cacheDir.absolutePath + "/logs"
@@ -388,27 +374,9 @@ class TunnelService : VpnService() {
}
}
fun updateStatusNotification(message: String?) {
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val chan =
NotificationChannel(
NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_NAME,
NotificationManager.IMPORTANCE_DEFAULT,
)
chan.description = "Firezone connection status"
manager.createNotificationChannel(chan)
val notificationBuilder = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
val notification =
notificationBuilder.setOngoing(true).setSmallIcon(R.drawable.ic_firezone_logo)
.setContentTitle(NOTIFICATION_TITLE).setContentText(message)
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setCategory(Notification.CATEGORY_SERVICE).setContentIntent(configIntent()).build()
startForeground(STATUS_NOTIFICATION_ID, notification)
fun updateStatusNotification(statusType: TunnelStatusNotification.StatusType) {
val notification = TunnelStatusNotification.update(this, statusType).build()
startForeground(TunnelStatusNotification.ID, notification)
}
private fun getDeviceName(): String {
@@ -427,11 +395,6 @@ class TunnelService : VpnService() {
DOWN,
}
private const val NOTIFICATION_CHANNEL_ID = "firezone-connection-status"
private const val NOTIFICATION_CHANNEL_NAME = "firezone-connection-status"
private const val STATUS_NOTIFICATION_ID = 1337
private const val NOTIFICATION_TITLE = "Firezone Connection Status"
private const val TAG: String = "TunnelService"
private const val SESSION_NAME: String = "Firezone Connection"
private const val MTU: Int = 1280

View File

@@ -0,0 +1,100 @@
/* Licensed under Apache 2.0 (C) 2024 Firezone, Inc. */
package dev.firezone.android.tunnel
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Context.NOTIFICATION_SERVICE
import android.content.Intent
import android.util.Log
import androidx.core.app.NotificationCompat
import dev.firezone.android.R
import dev.firezone.android.core.presentation.MainActivity
object TunnelStatusNotification {
private const val CHANNEL_ID = "firezone-connection-status"
private const val CHANNEL_NAME = "firezone-connection-status"
private const val CHANNEL_DESCRIPTION = "Firezone connection status"
const val ID = 1337
private const val TITLE = "Firezone Connection Status"
private const val TAG: String = "TunnelStatusNotification"
fun update(
context: Context,
status: StatusType,
): NotificationCompat.Builder {
Log.d(TAG, "update")
val manager = context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val chan =
NotificationChannel(
CHANNEL_ID,
CHANNEL_NAME,
NotificationManager.IMPORTANCE_DEFAULT,
)
chan.description = CHANNEL_DESCRIPTION
manager.createNotificationChannel(chan)
val notificationBuilder =
NotificationCompat.Builder(context, CHANNEL_ID)
.setContentIntent(configIntent(context))
return status.applySettings(notificationBuilder)
}
private fun configIntent(context: Context): PendingIntent {
Log.d(TAG, "configIntent")
val intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
return PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
data object SignedOut : StatusType() {
private const val MESSAGE = "Status: Signed out. Tap here to sign in."
override fun applySettings(builder: NotificationCompat.Builder) =
builder
.setSmallIcon(R.drawable.ic_firezone_logo)
.setContentTitle(TITLE)
.setContentText(MESSAGE)
.setCategory(NotificationCompat.CATEGORY_ERROR)
.setPriority(NotificationManager.IMPORTANCE_HIGH)
.setAutoCancel(true)
}
data object Connecting : StatusType() {
private const val MESSAGE = "Status: Connecting..."
override fun applySettings(builder: NotificationCompat.Builder) =
builder
.setSmallIcon(R.drawable.ic_firezone_logo)
.setContentTitle(TITLE)
.setContentText(MESSAGE)
.setCategory(Notification.CATEGORY_SERVICE)
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setOngoing(true)
}
data object Connected : StatusType() {
private const val MESSAGE = "Status: Connected"
override fun applySettings(builder: NotificationCompat.Builder) =
builder
.setSmallIcon(R.drawable.ic_firezone_logo)
.setContentTitle(TITLE)
.setContentText(MESSAGE)
.setCategory(Notification.CATEGORY_SERVICE)
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setOngoing(true)
}
sealed class StatusType {
abstract fun applySettings(builder: NotificationCompat.Builder): NotificationCompat.Builder
}
}