@ -70,7 +70,7 @@ class App : Application(), libtailscale.AppContext {
. addCapability ( NetworkCapabilities . NET _CAPABILITY _INTERNET )
. addCapability ( NetworkCapabilities . NET _CAPABILITY _INTERNET )
. addCapability ( NetworkCapabilities . NET _CAPABILITY _NOT _VPN )
. addCapability ( NetworkCapabilities . NET _CAPABILITY _NOT _VPN )
. build ( )
. build ( )
lateinit var appInstance : App
private lateinit var appInstance : App
@JvmStatic
@JvmStatic
fun startActivityForResult ( act : Activity , intent : Intent ? , request : Int ) {
fun startActivityForResult ( act : Activity , intent : Intent ? , request : Int ) {
@ -78,8 +78,13 @@ class App : Application(), libtailscale.AppContext {
f . startActivityForResult ( intent , request )
f . startActivityForResult ( intent , request )
}
}
/ * *
* Initializes the app ( if necessary ) and returns the singleton app instance . Always use this
* function to obtain an App reference to make sure the app initializes .
* /
@JvmStatic
@JvmStatic
fun getApplication ( ) : App {
fun getApplication ( ) : App {
appInstance . initOnce ( )
return appInstance
return appInstance
}
}
}
}
@ -98,6 +103,24 @@ class App : Application(), libtailscale.AppContext {
override fun onCreate ( ) {
override fun onCreate ( ) {
super . onCreate ( )
super . onCreate ( )
appInstance = this
}
override fun onTerminate ( ) {
super . onTerminate ( )
Notifier . stop ( )
applicationScope . cancel ( )
}
var initialized = false
@Synchronized
private fun initOnce ( ) {
if ( initialized ) {
return
}
initialized = true
val dataDir = this . filesDir . absolutePath
val dataDir = this . filesDir . absolutePath
// Set this to enable direct mode for taildrop whereby downloads will be saved directly
// Set this to enable direct mode for taildrop whereby downloads will be saved directly
@ -105,7 +128,6 @@ class App : Application(), libtailscale.AppContext {
// an app local directory "Taildrop" if we cannot create that. This mode does not support
// an app local directory "Taildrop" if we cannot create that. This mode does not support
// user notifications for incoming files.
// user notifications for incoming files.
val directFileDir = this . prepareDownloadsFolder ( )
val directFileDir = this . prepareDownloadsFolder ( )
app = Libtailscale . start ( dataDir , directFileDir . absolutePath , this )
app = Libtailscale . start ( dataDir , directFileDir . absolutePath , this )
Request . setApp ( app )
Request . setApp ( app )
Notifier . setApp ( app )
Notifier . setApp ( app )
@ -116,22 +138,15 @@ class App : Application(), libtailscale.AppContext {
STATUS _CHANNEL _ID , " VPN Status " , NotificationManagerCompat . IMPORTANCE _LOW )
STATUS _CHANNEL _ID , " VPN Status " , NotificationManagerCompat . IMPORTANCE _LOW )
createNotificationChannel (
createNotificationChannel (
FILE _CHANNEL _ID , " File transfers " , NotificationManagerCompat . IMPORTANCE _DEFAULT )
FILE _CHANNEL _ID , " File transfers " , NotificationManagerCompat . IMPORTANCE _DEFAULT )
appInstance = this
applicationScope . launch {
applicationScope . launch {
Notifier . connStatus . collect { connStatus -> updateConnStatus ( connStatus ) }
Notifier . connStatus . collect { connStatus -> updateConnStatus ( connStatus ) }
}
}
}
}
override fun onTerminate ( ) {
super . onTerminate ( )
Notifier . stop ( )
applicationScope . cancel ( )
}
fun setWantRunning ( wantRunning : Boolean ) {
fun setWantRunning ( wantRunning : Boolean ) {
val callback : ( Result < Ipn . Prefs > ) -> Unit = { result ->
val callback : ( Result < Ipn . Prefs > ) -> Unit = { result ->
result . fold (
result . fold (
onSuccess = { } ,
onSuccess = { } ,
onFailure = { error ->
onFailure = { error ->
Log . d ( " TAG " , " Set want running: failed to update preferences: ${error.message} " )
Log . d ( " TAG " , " Set want running: failed to update preferences: ${error.message} " )
} )
} )
@ -181,7 +196,6 @@ class App : Application(), libtailscale.AppContext {
startService ( intent )
startService ( intent )
}
}
// encryptToPref a byte array of data using the Jetpack Security
// encryptToPref a byte array of data using the Jetpack Security
// library and writes it to a global encrypted preference store.
// library and writes it to a global encrypted preference store.
@Throws ( IOException :: class , GeneralSecurityException :: class )
@Throws ( IOException :: class , GeneralSecurityException :: class )
@ -215,26 +229,17 @@ class App : Application(), libtailscale.AppContext {
QuickToggleService . setReady ( this , ready )
QuickToggleService . setReady ( this , ready )
Log . d ( " App " , " Set Tile Ready: $ready " )
Log . d ( " App " , " Set Tile Ready: $ready " )
val action = if ( ready ) IPNReceiver . INTENT _DISCONNECT _VPN else IPNReceiver . INTENT _CONNECT _VPN
val action = if ( ready ) IPNReceiver . INTENT _DISCONNECT _VPN else IPNReceiver . INTENT _CONNECT _VPN
val intent = Intent ( this , IPNReceiver :: class . java ) . apply {
val intent = Intent ( this , IPNReceiver :: class . java ) . apply { this . action = action }
this . action = action
val pendingIntent : PendingIntent =
}
PendingIntent . getBroadcast (
val pendingIntent : PendingIntent = PendingIntent . getBroadcast (
this , 0 , intent , PendingIntent . FLAG _UPDATE _CURRENT or PendingIntent . FLAG _IMMUTABLE )
this ,
if ( ready ) {
0 ,
intent ,
PendingIntent . FLAG _UPDATE _CURRENT or PendingIntent . FLAG _IMMUTABLE
)
if ( ready ) {
startVPN ( )
startVPN ( )
}
}
val notificationMessage = if ( ready ) getString ( R . string . connected ) else getString ( R . string . not _connected )
val notificationMessage =
if ( ready ) getString ( R . string . connected ) else getString ( R . string . not _connected )
notify (
notify (
" Tailscale " ,
" Tailscale " , notificationMessage , STATUS _CHANNEL _ID , pendingIntent , STATUS _NOTIFICATION _ID )
notificationMessage ,
STATUS _CHANNEL _ID ,
pendingIntent ,
STATUS _NOTIFICATION _ID
)
}
}
fun getHostname ( ) : String {
fun getHostname ( ) : String {
@ -337,7 +342,8 @@ class App : Application(), libtailscale.AppContext {
}
}
val pending : PendingIntent =
val pending : PendingIntent =
PendingIntent . getActivity ( this , 0 , viewIntent , PendingIntent . FLAG _UPDATE _CURRENT )
PendingIntent . getActivity ( this , 0 , viewIntent , PendingIntent . FLAG _UPDATE _CURRENT )
notify ( getString ( R . string . file _notification ) , msg , FILE _CHANNEL _ID , pending , FILE _NOTIFICATION _ID )
notify (
getString ( R . string . file _notification ) , msg , FILE _CHANNEL _ID , pending , FILE _NOTIFICATION _ID )
}
}
fun createNotificationChannel ( id : String ? , name : String ? , importance : Int ) {
fun createNotificationChannel ( id : String ? , name : String ? , importance : Int ) {
@ -346,7 +352,13 @@ class App : Application(), libtailscale.AppContext {
nm . createNotificationChannel ( channel )
nm . createNotificationChannel ( channel )
}
}
fun notify ( title : String ? , message : String ? , channel : String , intent : PendingIntent ? , notificationID : Int ) {
fun notify (
title : String ? ,
message : String ? ,
channel : String ,
intent : PendingIntent ? ,
notificationID : Int
) {
val builder : NotificationCompat . Builder =
val builder : NotificationCompat . Builder =
NotificationCompat . Builder ( this , channel )
NotificationCompat . Builder ( this , channel )
. setSmallIcon ( R . drawable . ic _notification )
. setSmallIcon ( R . drawable . ic _notification )