Files
vpnhotspotmod/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt
2018-09-07 11:35:09 +08:00

151 lines
6.0 KiB
Kotlin

package be.mygod.vpnhotspot.manage
import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
import android.net.wifi.WifiConfiguration
import android.net.wifi.p2p.WifiP2pGroup
import android.os.IBinder
import android.view.WindowManager
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDialog
import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf
import androidx.databinding.BaseObservable
import androidx.databinding.Bindable
import androidx.recyclerview.widget.RecyclerView
import be.mygod.vpnhotspot.*
import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.databinding.ListitemRepeaterBinding
import be.mygod.vpnhotspot.net.wifi.P2pSupplicantConfiguration
import be.mygod.vpnhotspot.net.wifi.WifiP2pDialogFragment
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
import be.mygod.vpnhotspot.util.formatAddresses
import be.mygod.vpnhotspot.widget.SmartSnackbar
import com.crashlytics.android.Crashlytics
import java.net.NetworkInterface
import java.net.SocketException
class RepeaterManager(private val parent: TetheringFragment) : Manager(), ServiceConnection {
class ViewHolder(val binding: ListitemRepeaterBinding) : RecyclerView.ViewHolder(binding.root)
inner class Data : BaseObservable() {
val switchEnabled: Boolean
@Bindable get() = when (binder?.service?.status) {
RepeaterService.Status.IDLE, RepeaterService.Status.ACTIVE -> true
else -> false
}
val serviceStarted: Boolean
@Bindable get() = when (binder?.service?.status) {
RepeaterService.Status.STARTING, RepeaterService.Status.ACTIVE -> true
else -> false
}
val ssid @Bindable get() = binder?.service?.group?.networkName ?: ""
val addresses: CharSequence @Bindable get() {
return try {
NetworkInterface.getByName(p2pInterface ?: return "")?.formatAddresses() ?: ""
} catch (e: SocketException) {
e.printStackTrace()
Crashlytics.logException(e)
""
}
}
var oc: CharSequence
@Bindable get() {
val oc = app.operatingChannel
return if (oc in 1..165) oc.toString() else ""
}
set(value) = app.pref.edit().putString(App.KEY_OPERATING_CHANNEL, value.toString()).apply()
fun onStatusChanged() {
notifyPropertyChanged(BR.switchEnabled)
notifyPropertyChanged(BR.serviceStarted)
notifyPropertyChanged(BR.addresses)
}
fun onGroupChanged(group: WifiP2pGroup? = null) {
notifyPropertyChanged(BR.ssid)
p2pInterface = group?.`interface`
notifyPropertyChanged(BR.addresses)
}
fun toggle() {
val binder = binder
when (binder?.service?.status) {
RepeaterService.Status.IDLE -> {
val context = parent.requireContext()
ContextCompat.startForegroundService(context, Intent(context, RepeaterService::class.java))
}
RepeaterService.Status.ACTIVE -> binder.shutdown()
else -> { }
}
}
fun wps() {
if (binder?.active != true) return
val dialog = AlertDialog.Builder(parent.requireContext())
.setTitle(R.string.repeater_wps_dialog_title)
.setView(R.layout.dialog_wps)
.setPositiveButton(android.R.string.ok) { dialog, _ ->
binder?.startWps((dialog as AppCompatDialog)
.findViewById<EditText>(android.R.id.edit)!!.text.toString())
}
.setNegativeButton(android.R.string.cancel, null)
.setNeutralButton(R.string.repeater_wps_dialog_pbc) { _, _ -> binder?.startWps(null) }
.create()
dialog.window!!.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
dialog.show()
}
fun editConfigurations() {
val binder = binder
val group = binder?.service?.group
val ssid = group?.networkName
if (ssid != null) {
val wifi = WifiConfiguration()
val conf = P2pSupplicantConfiguration()
wifi.SSID = ssid
wifi.preSharedKey = group.passphrase
if (wifi.preSharedKey == null) wifi.preSharedKey = conf.readPsk()
if (wifi.preSharedKey != null) {
WifiP2pDialogFragment().apply {
arguments = bundleOf(Pair(WifiP2pDialogFragment.KEY_CONFIGURATION, wifi),
Pair(WifiP2pDialogFragment.KEY_CONFIGURER, conf))
setTargetFragment(parent, 0)
}.show(parent.fragmentManager, WifiP2pDialogFragment.TAG)
return
}
}
SmartSnackbar.make(R.string.repeater_configure_failure).show()
}
}
init {
ServiceForegroundConnector(parent, this, RepeaterService::class)
}
override val type get() = VIEW_TYPE_REPEATER
private val data = Data()
internal var binder: RepeaterService.Binder? = null
private var p2pInterface: String? = null
override fun bindTo(viewHolder: RecyclerView.ViewHolder) {
(viewHolder as ViewHolder).binding.data = data
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
binder = service as RepeaterService.Binder
service.statusChanged[this] = data::onStatusChanged
service.groupChanged[this] = data::onGroupChanged
data.notifyChange()
}
override fun onServiceDisconnected(name: ComponentName?) {
val binder = binder ?: return
this.binder = null
binder.statusChanged -= this
binder.groupChanged -= this
data.onStatusChanged()
}
}