Refactor WifiP2pDialog as DialogFragment
This commit is contained in:
@@ -11,7 +11,7 @@ android {
|
|||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
resConfigs "zh-rCN"
|
resConfigs "zh-rCN"
|
||||||
versionCode 29
|
versionCode 30
|
||||||
versionName "1.3.5"
|
versionName "1.3.5"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package be.mygod.vpnhotspot.manage
|
package be.mygod.vpnhotspot.manage
|
||||||
|
|
||||||
import android.annotation.TargetApi
|
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.DialogInterface
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.ServiceConnection
|
import android.content.ServiceConnection
|
||||||
import android.net.wifi.WifiConfiguration
|
import android.net.wifi.WifiConfiguration
|
||||||
@@ -13,6 +11,7 @@ import android.widget.EditText
|
|||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatDialog
|
import androidx.appcompat.app.AppCompatDialog
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import androidx.databinding.BaseObservable
|
import androidx.databinding.BaseObservable
|
||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
@@ -20,7 +19,7 @@ import be.mygod.vpnhotspot.*
|
|||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
import be.mygod.vpnhotspot.databinding.ListitemRepeaterBinding
|
import be.mygod.vpnhotspot.databinding.ListitemRepeaterBinding
|
||||||
import be.mygod.vpnhotspot.net.wifi.P2pSupplicantConfiguration
|
import be.mygod.vpnhotspot.net.wifi.P2pSupplicantConfiguration
|
||||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pDialog
|
import be.mygod.vpnhotspot.net.wifi.WifiP2pDialogFragment
|
||||||
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
|
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
|
||||||
import be.mygod.vpnhotspot.util.formatAddresses
|
import be.mygod.vpnhotspot.util.formatAddresses
|
||||||
import com.crashlytics.android.Crashlytics
|
import com.crashlytics.android.Crashlytics
|
||||||
@@ -111,18 +110,11 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
|||||||
wifi.preSharedKey = conf.readPsk { mainActivity.snackbar(it.message.toString()).show() }
|
wifi.preSharedKey = conf.readPsk { mainActivity.snackbar(it.message.toString()).show() }
|
||||||
}
|
}
|
||||||
if (wifi.preSharedKey != null) {
|
if (wifi.preSharedKey != null) {
|
||||||
var dialog: WifiP2pDialog? = null
|
WifiP2pDialogFragment().apply {
|
||||||
dialog = WifiP2pDialog(mainActivity, DialogInterface.OnClickListener { _, which ->
|
arguments = bundleOf(Pair(WifiP2pDialogFragment.KEY_CONFIGURATION, wifi),
|
||||||
when (which) {
|
Pair(WifiP2pDialogFragment.KEY_CONFIGURER, conf))
|
||||||
DialogInterface.BUTTON_POSITIVE -> @TargetApi(23) when (conf.update(dialog!!.config!!)) {
|
setTargetFragment(parent, 0)
|
||||||
true -> app.handler.postDelayed(binder::requestGroupUpdate, 1000)
|
}.show(parent.fragmentManager, WifiP2pDialogFragment.TAG)
|
||||||
false -> mainActivity.snackbar().setText(R.string.noisy_su_failure).show()
|
|
||||||
null -> mainActivity.snackbar().setText(R.string.root_unavailable).show()
|
|
||||||
}
|
|
||||||
DialogInterface.BUTTON_NEUTRAL -> binder.resetCredentials()
|
|
||||||
}
|
|
||||||
}, wifi)
|
|
||||||
dialog.show()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +128,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
|||||||
|
|
||||||
override val type get() = VIEW_TYPE_REPEATER
|
override val type get() = VIEW_TYPE_REPEATER
|
||||||
private val data = Data()
|
private val data = Data()
|
||||||
private var binder: RepeaterService.Binder? = null
|
internal var binder: RepeaterService.Binder? = null
|
||||||
private var p2pInterface: String? = null
|
private var p2pInterface: String? = null
|
||||||
|
|
||||||
override fun bindTo(viewHolder: RecyclerView.ViewHolder) {
|
override fun bindTo(viewHolder: RecyclerView.ViewHolder) {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class TetheringFragment : Fragment(), ServiceConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inner class ManagerAdapter : ListAdapter<Manager, RecyclerView.ViewHolder>(Manager) {
|
inner class ManagerAdapter : ListAdapter<Manager, RecyclerView.ViewHolder>(Manager) {
|
||||||
private val repeaterManager by lazy { RepeaterManager(this@TetheringFragment) }
|
internal val repeaterManager by lazy { RepeaterManager(this@TetheringFragment) }
|
||||||
private val localOnlyHotspotManager by lazy @TargetApi(26) { LocalOnlyHotspotManager(this@TetheringFragment) }
|
private val localOnlyHotspotManager by lazy @TargetApi(26) { LocalOnlyHotspotManager(this@TetheringFragment) }
|
||||||
private val tetherManagers by lazy @TargetApi(24) {
|
private val tetherManagers by lazy @TargetApi(24) {
|
||||||
listOf(TetherManager.Wifi(this@TetheringFragment),
|
listOf(TetherManager.Wifi(this@TetheringFragment),
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package be.mygod.vpnhotspot.net.wifi
|
package be.mygod.vpnhotspot.net.wifi
|
||||||
|
|
||||||
import android.net.wifi.WifiConfiguration
|
import android.net.wifi.WifiConfiguration
|
||||||
|
import android.os.Parcel
|
||||||
|
import android.os.Parcelable
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
@@ -9,8 +11,11 @@ import be.mygod.vpnhotspot.util.noisySu
|
|||||||
import com.crashlytics.android.Crashlytics
|
import com.crashlytics.android.Crashlytics
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class P2pSupplicantConfiguration {
|
class P2pSupplicantConfiguration(private val initContent: String? = null) : Parcelable {
|
||||||
companion object {
|
companion object CREATOR : Parcelable.Creator<P2pSupplicantConfiguration> {
|
||||||
|
override fun createFromParcel(parcel: Parcel) = P2pSupplicantConfiguration(parcel.readString())
|
||||||
|
override fun newArray(size: Int): Array<P2pSupplicantConfiguration?> = arrayOfNulls(size)
|
||||||
|
|
||||||
private const val TAG = "P2pSupplicationConf"
|
private const val TAG = "P2pSupplicationConf"
|
||||||
/**
|
/**
|
||||||
* Format for ssid is much more complicated, therefore we are only trying to find the line and rely on
|
* Format for ssid is much more complicated, therefore we are only trying to find the line and rely on
|
||||||
@@ -25,7 +30,13 @@ class P2pSupplicantConfiguration {
|
|||||||
private val pskParser = "^[\\r\\t ]*psk=(ext:|\"(.*)\"|\"(.*)|[0-9a-fA-F]{64}\$)".toRegex(RegexOption.MULTILINE)
|
private val pskParser = "^[\\r\\t ]*psk=(ext:|\"(.*)\"|\"(.*)|[0-9a-fA-F]{64}\$)".toRegex(RegexOption.MULTILINE)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val content by lazy { loggerSu("cat /data/misc/wifi/p2p_supplicant.conf") }
|
override fun writeToParcel(out: Parcel, flags: Int) {
|
||||||
|
out.writeString(if (contentDelegate.isInitialized()) content else null)
|
||||||
|
}
|
||||||
|
override fun describeContents() = 0
|
||||||
|
|
||||||
|
private val contentDelegate = lazy { initContent ?: loggerSu("cat /data/misc/wifi/p2p_supplicant.conf") }
|
||||||
|
private val content by contentDelegate
|
||||||
|
|
||||||
fun readPsk(handler: ((RuntimeException) -> Unit)? = null): String? {
|
fun readPsk(handler: ((RuntimeException) -> Unit)? = null): String? {
|
||||||
return try {
|
return try {
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
package be.mygod.vpnhotspot.net.wifi
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.DialogInterface
|
|
||||||
import android.net.wifi.WifiConfiguration
|
|
||||||
import android.net.wifi.WifiConfiguration.AuthAlgorithm
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import android.text.Editable
|
|
||||||
import android.text.TextWatcher
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.EditText
|
|
||||||
import android.widget.TextView
|
|
||||||
import be.mygod.vpnhotspot.R
|
|
||||||
import java.nio.charset.Charset
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://android.googlesource.com/platform/packages/apps/Settings/+/39b4674/src/com/android/settings/wifi/WifiApDialog.java
|
|
||||||
*/
|
|
||||||
class WifiP2pDialog(mContext: Context, private val mListener: DialogInterface.OnClickListener,
|
|
||||||
private val mWifiConfig: WifiConfiguration?) : AlertDialog(mContext), TextWatcher {
|
|
||||||
companion object {
|
|
||||||
private const val BUTTON_SUBMIT = DialogInterface.BUTTON_POSITIVE
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var mView: View
|
|
||||||
private lateinit var mSsid: TextView
|
|
||||||
private lateinit var mPassword: EditText
|
|
||||||
val config: WifiConfiguration?
|
|
||||||
get() {
|
|
||||||
val config = WifiConfiguration()
|
|
||||||
config.SSID = mSsid.text.toString()
|
|
||||||
config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN)
|
|
||||||
if (mPassword.length() != 0) {
|
|
||||||
val password = mPassword.text.toString()
|
|
||||||
config.preSharedKey = password
|
|
||||||
}
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
mView = layoutInflater.inflate(R.layout.dialog_wifi_ap, null)
|
|
||||||
setView(mView)
|
|
||||||
val context = context
|
|
||||||
setTitle(R.string.repeater_configure)
|
|
||||||
mSsid = mView.findViewById(R.id.ssid)
|
|
||||||
mPassword = mView.findViewById(R.id.password)
|
|
||||||
// Note: Reading persistent group information in p2p_supplicant.conf wasn't available until this commit:
|
|
||||||
// https://android.googlesource.com/platform/external/wpa_supplicant_8/+/216983bceec7c450951e2fbcd076b5c75d432e57%5E%21/
|
|
||||||
// which isn't merged until Android 6.0.
|
|
||||||
if (Build.VERSION.SDK_INT >= 23) setButton(BUTTON_SUBMIT, context.getString(R.string.wifi_save), mListener)
|
|
||||||
setButton(DialogInterface.BUTTON_NEGATIVE,
|
|
||||||
context.getString(R.string.wifi_cancel), mListener)
|
|
||||||
setButton(DialogInterface.BUTTON_NEUTRAL, context.getString(R.string.repeater_reset_credentials), mListener)
|
|
||||||
if (mWifiConfig != null) {
|
|
||||||
mSsid.text = mWifiConfig.SSID
|
|
||||||
mPassword.setText(mWifiConfig.preSharedKey)
|
|
||||||
}
|
|
||||||
mSsid.addTextChangedListener(this)
|
|
||||||
mPassword.addTextChangedListener(this)
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
validate()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun validate() {
|
|
||||||
val mSsidString = mSsid.text.toString()
|
|
||||||
val ssidValid = mSsid.length() != 0 && Charset.forName("UTF-8").encode(mSsidString).limit() <= 32
|
|
||||||
val passwordValid = mPassword.length() >= 8
|
|
||||||
mView.findViewById<TextInputLayout>(R.id.password_wrapper).error =
|
|
||||||
if (passwordValid) null else context.getString(R.string.credentials_password_too_short)
|
|
||||||
getButton(BUTTON_SUBMIT).isEnabled = ssidValid && passwordValid
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { }
|
|
||||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { }
|
|
||||||
override fun afterTextChanged(editable: Editable) {
|
|
||||||
validate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package be.mygod.vpnhotspot.net.wifi
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.net.wifi.WifiConfiguration
|
||||||
|
import android.net.wifi.WifiConfiguration.AuthAlgorithm
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.Editable
|
||||||
|
import android.text.TextWatcher
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.EditText
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
|
import be.mygod.vpnhotspot.MainActivity
|
||||||
|
import be.mygod.vpnhotspot.R
|
||||||
|
import be.mygod.vpnhotspot.manage.TetheringFragment
|
||||||
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://android.googlesource.com/platform/packages/apps/Settings/+/39b4674/src/com/android/settings/wifi/WifiApDialog.java
|
||||||
|
*/
|
||||||
|
class WifiP2pDialogFragment : DialogFragment(), TextWatcher, DialogInterface.OnClickListener {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "WifiP2pDialogFragment"
|
||||||
|
const val KEY_CONFIGURATION = "configuration"
|
||||||
|
const val KEY_CONFIGURER = "configurer"
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var mView: View
|
||||||
|
private lateinit var mSsid: TextView
|
||||||
|
private lateinit var mPassword: EditText
|
||||||
|
private lateinit var configurer: P2pSupplicantConfiguration
|
||||||
|
private val config: WifiConfiguration?
|
||||||
|
get() {
|
||||||
|
val config = WifiConfiguration()
|
||||||
|
config.SSID = mSsid.text.toString()
|
||||||
|
config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN)
|
||||||
|
if (mPassword.length() != 0) {
|
||||||
|
val password = mPassword.text.toString()
|
||||||
|
config.preSharedKey = password
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): AlertDialog {
|
||||||
|
return AlertDialog.Builder(requireContext()).apply {
|
||||||
|
mView = requireActivity().layoutInflater.inflate(R.layout.dialog_wifi_ap, null)
|
||||||
|
setView(mView)
|
||||||
|
setTitle(R.string.repeater_configure)
|
||||||
|
mSsid = mView.findViewById(R.id.ssid)
|
||||||
|
mPassword = mView.findViewById(R.id.password)
|
||||||
|
// Note: Reading persistent group information in p2p_supplicant.conf wasn't available until this commit:
|
||||||
|
// https://android.googlesource.com/platform/external/wpa_supplicant_8/+/216983bceec7c450951e2fbcd076b5c75d432e57%5E%21/
|
||||||
|
// which isn't merged until Android 6.0.
|
||||||
|
if (Build.VERSION.SDK_INT >= 23) {
|
||||||
|
setPositiveButton(context.getString(R.string.wifi_save), this@WifiP2pDialogFragment)
|
||||||
|
}
|
||||||
|
setNegativeButton(context.getString(R.string.wifi_cancel), this@WifiP2pDialogFragment)
|
||||||
|
setNeutralButton(context.getString(R.string.repeater_reset_credentials), this@WifiP2pDialogFragment)
|
||||||
|
val arguments = arguments!!
|
||||||
|
configurer = arguments.getParcelable(KEY_CONFIGURER)
|
||||||
|
val mWifiConfig = arguments.getParcelable<WifiConfiguration>(KEY_CONFIGURATION)
|
||||||
|
if (mWifiConfig != null) {
|
||||||
|
mSsid.text = mWifiConfig.SSID
|
||||||
|
mPassword.setText(mWifiConfig.preSharedKey)
|
||||||
|
}
|
||||||
|
mSsid.addTextChangedListener(this@WifiP2pDialogFragment)
|
||||||
|
mPassword.addTextChangedListener(this@WifiP2pDialogFragment)
|
||||||
|
}.create()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
validate()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validate() {
|
||||||
|
val mSsidString = mSsid.text.toString()
|
||||||
|
val ssidValid = mSsid.length() != 0 && Charset.forName("UTF-8").encode(mSsidString).limit() <= 32
|
||||||
|
val passwordValid = mPassword.length() >= 8
|
||||||
|
mView.findViewById<TextInputLayout>(R.id.password_wrapper).error =
|
||||||
|
if (passwordValid) null else requireContext().getString(R.string.credentials_password_too_short)
|
||||||
|
(dialog as AlertDialog).getButton(DialogInterface.BUTTON_POSITIVE).isEnabled = ssidValid && passwordValid
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { }
|
||||||
|
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { }
|
||||||
|
override fun afterTextChanged(editable: Editable) = validate()
|
||||||
|
|
||||||
|
override fun onClick(dialog: DialogInterface?, which: Int) {
|
||||||
|
when (which) {
|
||||||
|
DialogInterface.BUTTON_POSITIVE -> @TargetApi(23) when (configurer.update(config!!)) {
|
||||||
|
true -> {
|
||||||
|
app.handler.postDelayed((targetFragment as TetheringFragment).adapter.repeaterManager
|
||||||
|
.binder!!::requestGroupUpdate, 1000)
|
||||||
|
}
|
||||||
|
false -> (activity as MainActivity).snackbar().setText(R.string.noisy_su_failure).show()
|
||||||
|
null -> (activity as MainActivity).snackbar().setText(R.string.root_unavailable).show()
|
||||||
|
}
|
||||||
|
DialogInterface.BUTTON_NEUTRAL -> {
|
||||||
|
(targetFragment as TetheringFragment).adapter.repeaterManager.binder!!.resetCredentials()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user