Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class SecureDataModeVpnService :
- VpnService(),
- Handler.Callback {
- private var vpnThread: SecureThread = SecureThread(this)
- private val connectivityChangedReceiver: BroadcastReceiver =
- object : BroadcastReceiver() {
- override fun onReceive(
- context: Context,
- intent: Intent,
- ) {
- onConnectivityChanged(intent)
- }
- }
- private val stopSignalBroadcastReceiver: BroadcastReceiver =
- object : BroadcastReceiver() {
- override fun onReceive(
- context: Context?,
- intent: Intent,
- ) {
- if (STOP_MESSAGE == intent.action) {
- debugLog("Received stop signal via stopSignalBroadcastReceiver")
- onRevoke()
- }
- }
- }
- override fun onStartCommand(
- intent: Intent?,
- flags: Int,
- startId: Int,
- ): Int {
- debugLog("Received start command")
- if (intent?.action == STOP_MESSAGE) {
- debugLog("Received STOP_MESSAGE via intent action")
- onRevoke()
- return START_NOT_STICKY
- }
- val notif = buildVpnNotification()
- // Must call startForeground within ~5s or system kills the app
- startForeground(NOTIF_ID, notif)
- debugLog("Started foreground service")
- startVpn()
- return Service.START_STICKY
- }
- private fun buildVpnNotification(): Notification {
- debugLog("Building notification channel for foreground service")
- val disconnectIntent =
- Intent(this, SecureDataModeVpnService::class.java).apply {
- action = STOP_MESSAGE
- }
- val pending =
- PendingIntent.getBroadcast(
- this,
- 0,
- disconnectIntent,
- PendingIntent.FLAG_IMMUTABLE,
- )
- return NotificationCompat
- .Builder(this, CHANNEL_ID)
- .setContentTitle("Secure Data Mode")
- .setContentText("VPN is active")
- .setSmallIcon(android.R.drawable.ic_secure)
- .addAction(
- android.R.drawable.ic_delete,
- "Disconnect",
- pending,
- ).setOngoing(true)
- .setOnlyAlertOnce(true)
- .build()
- }
- override fun handleMessage(message: Message): Boolean {
- // when (message.what) {
- // SecureMessage -> updateVpnStatus(message.arg1)
- // VPN_MSG_NETWORK_CHANGED -> connectivityChanged(message.obj as Intent)
- // else -> throw java.lang.IllegalArgumentException("Invalid message with what = " + message.what)
- // }
- return true
- }
- override fun onCreate() {
- super.onCreate()
- buildNotificationChannel()
- LocalBroadcastManager.getInstance(this).registerReceiver(
- stopSignalBroadcastReceiver,
- IntentFilter(STOP_MESSAGE),
- )
- registerReceiver(
- connectivityChangedReceiver,
- IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION),
- )
- }
- private fun buildNotificationChannel() {
- // start foreground notification, mandatory on newer
- // android versions
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- NotificationChannel(
- CHANNEL_ID,
- "Secure VPN",
- NotificationManager.IMPORTANCE_LOW,
- ).apply {
- description = "Running Secure Data VPN"
- lockscreenVisibility = Notification.VISIBILITY_PRIVATE
- }.also { channel ->
- getSystemService(NotificationManager::class.java)
- .createNotificationChannel(channel)
- }
- }
- }
- override fun onRevoke() {
- debugLog("Executing onRevoke()...")
- stopVpn()
- super.onRevoke()
- }
- override fun onDestroy() {
- stopVpn()
- super.onDestroy()
- }
- private fun startVpn() {
- debugLog("Starting VPN Service..")
- status = Status.STARTING
- vpnThread.startThread()
- }
- private fun restartVpn() {
- debugLog("Restarting VPN service")
- vpnThread.stopThread()
- vpnThread.startThread()
- }
- private fun stopVpn() {
- debugLog("Stopping VPN service")
- vpnThread.stopThread()
- try {
- LocalBroadcastManager.getInstance(this).unregisterReceiver(stopSignalBroadcastReceiver)
- debugLog("Unregistered stopSignalBroadcastReceiver")
- } catch (_: IllegalArgumentException) {
- debugLog("stopSignalBroadcastReceiver already unregistered.")
- }
- try {
- unregisterReceiver(connectivityChangedReceiver)
- debugLog("Unregistered connectivityChangedReceiver")
- } catch (_: IllegalArgumentException) {
- debugLog("connectivityChangedReceiver already unregistered.")
- }
- status = Status.STOPPED
- stopSelf()
- debugLog("Stopped VPN service")
- }
- private fun waitForNetwork() {
- status = Status.WAITING_FOR_NETWORK
- debugLog("Waiting for network...")
- vpnThread.stopThread()
- }
- private fun onConnectivityChanged(intent: Intent) {
- // todo:sp use network capabilities, tranasport_vpn instead
- if (intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 0) == ConnectivityManager.TYPE_VPN) {
- return
- }
- if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
- debugLog("No internet connection")
- waitForNetwork()
- } else {
- status = Status.RECONNECTING
- debugLog("Reconnecting to network...")
- restartVpn()
- }
- }
- private fun debugLog(msg: String) {
- Timber.d("$TAG-${SecureDataModeVpnService::class.simpleName}:: $msg")
- }
- companion object {
- const val TAG = "SecureDataMode"
- const val VPN_PERMISSION_REQUEST_CODE = 666
- const val STOP_MESSAGE = "STOP"
- var status = Status.STOPPED
- const val CHANNEL_ID = "secure_vpn_channel"
- const val NOTIF_ID = 79467
- }
- enum class Status {
- STARTING,
- RUNNING,
- STOPPING,
- STOPPED,
- RECONNECTING,
- WAITING_FOR_NETWORK,
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement