Initial commit
Hotspot works. VPN not yet.
This commit is contained in:
15
mobile/src/main/java/be/mygod/vpnhotspot/App.kt
Normal file
15
mobile/src/main/java/be/mygod/vpnhotspot/App.kt
Normal file
@@ -0,0 +1,15 @@
|
||||
package be.mygod.vpnhotspot
|
||||
|
||||
import android.app.Application
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.os.Build
|
||||
|
||||
class App : Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
if (Build.VERSION.SDK_INT >= 26) getSystemService(NotificationManager::class.java)
|
||||
.createNotificationChannel(NotificationChannel(HotspotService.CHANNEL,
|
||||
"Hotspot Service", NotificationManager.IMPORTANCE_LOW))
|
||||
}
|
||||
}
|
||||
156
mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt
Normal file
156
mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt
Normal file
@@ -0,0 +1,156 @@
|
||||
package be.mygod.vpnhotspot
|
||||
|
||||
import android.app.Service
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.wifi.p2p.WifiP2pGroup
|
||||
import android.net.wifi.p2p.WifiP2pManager
|
||||
import android.os.Binder
|
||||
import android.os.Looper
|
||||
import android.support.v4.app.NotificationCompat
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
|
||||
class HotspotService : Service(), WifiP2pManager.ChannelListener {
|
||||
companion object {
|
||||
const val CHANNEL = "hotspot"
|
||||
private const val TAG = "HotspotService"
|
||||
}
|
||||
|
||||
enum class Status {
|
||||
IDLE, STARTING, ACTIVE
|
||||
}
|
||||
|
||||
inner class HotspotBinder : Binder() {
|
||||
val service get() = this@HotspotService
|
||||
val status get() = this@HotspotService.status
|
||||
var data: MainActivity.Data? = null
|
||||
|
||||
fun shutdown() {
|
||||
p2pManager.removeGroup(channel, object : WifiP2pManager.ActionListener {
|
||||
override fun onSuccess() = clean()
|
||||
override fun onFailure(reason: Int) {
|
||||
Toast.makeText(this@HotspotService, "Failed to remove P2P group (reason: $reason)",
|
||||
Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var p2pManager: WifiP2pManager
|
||||
private lateinit var channel: WifiP2pManager.Channel
|
||||
private lateinit var group: WifiP2pGroup
|
||||
private var receiver: BroadcastReceiver? = null
|
||||
private val binder = HotspotBinder()
|
||||
|
||||
private var status = Status.IDLE
|
||||
set(value) {
|
||||
field = value
|
||||
binder.data?.onStatusChanged()
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent) = binder
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
p2pManager = getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager
|
||||
onChannelDisconnected()
|
||||
}
|
||||
|
||||
override fun onChannelDisconnected() {
|
||||
channel = p2pManager.initialize(this, Looper.getMainLooper(), this)
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
if (status != Status.IDLE) return START_NOT_STICKY
|
||||
status = Status.STARTING
|
||||
initReceiver()
|
||||
p2pManager.requestGroupInfo(channel, {
|
||||
when {
|
||||
it == null -> doStart()
|
||||
it.isGroupOwner -> doStart(it)
|
||||
else -> {
|
||||
Log.i(TAG, "Removing old group ($it)")
|
||||
p2pManager.removeGroup(channel, object : WifiP2pManager.ActionListener {
|
||||
override fun onSuccess() = doStart()
|
||||
override fun onFailure(reason: Int) {
|
||||
Toast.makeText(this@HotspotService, "Failed to remove old P2P group (reason: $reason)",
|
||||
Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
private fun doStart() {
|
||||
p2pManager.createGroup(channel, object : WifiP2pManager.ActionListener, WifiP2pManager.GroupInfoListener {
|
||||
private fun shutdown() {
|
||||
startForeground(0, NotificationCompat.Builder(this@HotspotService, CHANNEL)
|
||||
.build())
|
||||
clean()
|
||||
}
|
||||
|
||||
private var tries = 0
|
||||
override fun onSuccess() = p2pManager.requestGroupInfo(channel, this)
|
||||
override fun onGroupInfoAvailable(group: WifiP2pGroup?) {
|
||||
if (group != null && group.isGroupOwner) doStart(group) else if (tries < 10) {
|
||||
Thread.sleep(30L shl tries++)
|
||||
onSuccess()
|
||||
} else {
|
||||
Log.w(TAG, "Unexpected group: $group")
|
||||
shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(reason: Int) {
|
||||
Toast.makeText(this@HotspotService, "Failed to create P2P group (reason: $reason)",
|
||||
Toast.LENGTH_SHORT).show()
|
||||
shutdown()
|
||||
}
|
||||
})
|
||||
}
|
||||
private fun doStart(group: WifiP2pGroup) {
|
||||
status = Status.ACTIVE
|
||||
this.group = group
|
||||
startForeground(1, NotificationCompat.Builder(this@HotspotService, CHANNEL)
|
||||
.setColor(ContextCompat.getColor(this@HotspotService, R.color.colorPrimary))
|
||||
.setContentTitle(group.networkName)
|
||||
.setSubText(group.passphrase)
|
||||
.setSmallIcon(R.drawable.ic_device_wifi_tethering)
|
||||
.build())
|
||||
}
|
||||
|
||||
private fun initReceiver() {
|
||||
return
|
||||
receiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
when (intent.action) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
registerReceiver(receiver, createIntentFilter(
|
||||
WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION,
|
||||
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION,
|
||||
WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION,
|
||||
WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION))
|
||||
}
|
||||
|
||||
private fun clean() {
|
||||
status = Status.IDLE
|
||||
stopForeground(true)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
if (status != Status.IDLE) binder.shutdown()
|
||||
if (receiver != null) {
|
||||
unregisterReceiver(receiver)
|
||||
receiver = null
|
||||
}
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
80
mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt
Normal file
80
mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt
Normal file
@@ -0,0 +1,80 @@
|
||||
package be.mygod.vpnhotspot
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.databinding.BaseObservable
|
||||
import android.databinding.Bindable
|
||||
import android.databinding.DataBindingUtil
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import be.mygod.vpnhotspot.databinding.MainActivityBinding
|
||||
|
||||
class MainActivity : AppCompatActivity(), ServiceConnection {
|
||||
inner class Data : BaseObservable() {
|
||||
val switchEnabled: Boolean
|
||||
@Bindable get() = when (binder?.status) {
|
||||
HotspotService.Status.IDLE -> true
|
||||
HotspotService.Status.ACTIVE -> true
|
||||
else -> false
|
||||
}
|
||||
var serviceStarted: Boolean
|
||||
@Bindable get() = when (binder?.status) {
|
||||
HotspotService.Status.STARTING -> true
|
||||
HotspotService.Status.ACTIVE -> true
|
||||
else -> false
|
||||
}
|
||||
set(value) {
|
||||
val binder = binder
|
||||
when (binder?.status) {
|
||||
HotspotService.Status.IDLE ->
|
||||
ContextCompat.startForegroundService(this@MainActivity,
|
||||
Intent(this@MainActivity, HotspotService::class.java))
|
||||
HotspotService.Status.ACTIVE -> binder.shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
fun onStatusChanged() {
|
||||
notifyPropertyChanged(BR.switchEnabled)
|
||||
notifyPropertyChanged(BR.serviceStarted)
|
||||
}
|
||||
fun onBinderChanged() {
|
||||
onStatusChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var binding: MainActivityBinding
|
||||
private val data = Data()
|
||||
private var binder: HotspotService.HotspotBinder? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = DataBindingUtil.setContentView(this, R.layout.main_activity)
|
||||
binding.data = data
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
bindService(Intent(this, HotspotService::class.java), this, Context.BIND_AUTO_CREATE)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
unbindService(this)
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
||||
val binder = service as HotspotService.HotspotBinder
|
||||
binder.data = data
|
||||
this.binder = binder
|
||||
data.onBinderChanged()
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(name: ComponentName?) {
|
||||
binder?.data = null
|
||||
binder = null
|
||||
}
|
||||
}
|
||||
9
mobile/src/main/java/be/mygod/vpnhotspot/Utils.kt
Normal file
9
mobile/src/main/java/be/mygod/vpnhotspot/Utils.kt
Normal file
@@ -0,0 +1,9 @@
|
||||
package be.mygod.vpnhotspot
|
||||
|
||||
import android.content.IntentFilter
|
||||
|
||||
fun createIntentFilter(vararg actions: String): IntentFilter {
|
||||
val result = IntentFilter()
|
||||
actions.forEach { result.addAction(it) }
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user