From b526de681e2d568aba4ce277cd7fc8092d2b00fd Mon Sep 17 00:00:00 2001 From: Mygod Date: Sat, 21 Jul 2018 18:26:14 +0800 Subject: [PATCH] Refactor WifiP2pDialog as DialogFragment --- mobile/build.gradle | 2 +- .../vpnhotspot/manage/RepeaterManager.kt | 24 ++-- .../vpnhotspot/manage/TetheringFragment.kt | 2 +- .../net/wifi/P2pSupplicantConfiguration.kt | 17 ++- .../vpnhotspot/net/wifi/WifiP2pDialog.kt | 81 ------------- .../net/wifi/WifiP2pDialogFragment.kt | 109 ++++++++++++++++++ 6 files changed, 133 insertions(+), 102 deletions(-) delete mode 100644 mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialog.kt create mode 100644 mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialogFragment.kt diff --git a/mobile/build.gradle b/mobile/build.gradle index a6d3d8b0..c9c17518 100644 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -11,7 +11,7 @@ android { minSdkVersion 21 targetSdkVersion 28 resConfigs "zh-rCN" - versionCode 29 + versionCode 30 versionName "1.3.5" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt index 4bcf482c..8c2e8492 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt @@ -1,8 +1,6 @@ package be.mygod.vpnhotspot.manage -import android.annotation.TargetApi import android.content.ComponentName -import android.content.DialogInterface import android.content.Intent import android.content.ServiceConnection import android.net.wifi.WifiConfiguration @@ -13,6 +11,7 @@ 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 @@ -20,7 +19,7 @@ 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.WifiP2pDialog +import be.mygod.vpnhotspot.net.wifi.WifiP2pDialogFragment import be.mygod.vpnhotspot.util.ServiceForegroundConnector import be.mygod.vpnhotspot.util.formatAddresses 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() } } if (wifi.preSharedKey != null) { - var dialog: WifiP2pDialog? = null - dialog = WifiP2pDialog(mainActivity, DialogInterface.OnClickListener { _, which -> - when (which) { - DialogInterface.BUTTON_POSITIVE -> @TargetApi(23) when (conf.update(dialog!!.config!!)) { - true -> app.handler.postDelayed(binder::requestGroupUpdate, 1000) - 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() + WifiP2pDialogFragment().apply { + arguments = bundleOf(Pair(WifiP2pDialogFragment.KEY_CONFIGURATION, wifi), + Pair(WifiP2pDialogFragment.KEY_CONFIGURER, conf)) + setTargetFragment(parent, 0) + }.show(parent.fragmentManager, WifiP2pDialogFragment.TAG) return } } @@ -136,7 +128,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic override val type get() = VIEW_TYPE_REPEATER private val data = Data() - private var binder: RepeaterService.Binder? = null + internal var binder: RepeaterService.Binder? = null private var p2pInterface: String? = null override fun bindTo(viewHolder: RecyclerView.ViewHolder) { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetheringFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetheringFragment.kt index 4c053fe1..16be63c6 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetheringFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetheringFragment.kt @@ -36,7 +36,7 @@ class TetheringFragment : Fragment(), ServiceConnection { } inner class ManagerAdapter : ListAdapter(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 tetherManagers by lazy @TargetApi(24) { listOf(TetherManager.Wifi(this@TetheringFragment), diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/P2pSupplicantConfiguration.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/P2pSupplicantConfiguration.kt index 514db340..a9e6f391 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/P2pSupplicantConfiguration.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/P2pSupplicantConfiguration.kt @@ -1,6 +1,8 @@ package be.mygod.vpnhotspot.net.wifi import android.net.wifi.WifiConfiguration +import android.os.Parcel +import android.os.Parcelable import android.util.Log import androidx.annotation.RequiresApi import be.mygod.vpnhotspot.App.Companion.app @@ -9,8 +11,11 @@ import be.mygod.vpnhotspot.util.noisySu import com.crashlytics.android.Crashlytics import java.io.File -class P2pSupplicantConfiguration { - companion object { +class P2pSupplicantConfiguration(private val initContent: String? = null) : Parcelable { + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel) = P2pSupplicantConfiguration(parcel.readString()) + override fun newArray(size: Int): Array = arrayOfNulls(size) + private const val TAG = "P2pSupplicationConf" /** * 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 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? { return try { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialog.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialog.kt deleted file mode 100644 index 60642868..00000000 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialog.kt +++ /dev/null @@ -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(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() - } -} diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialogFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialogFragment.kt new file mode 100644 index 00000000..e5da0522 --- /dev/null +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pDialogFragment.kt @@ -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(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(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() + } + } + } +}