From 5e97e3d9aeb8164b6f3cb520fec2e67382ac293e Mon Sep 17 00:00:00 2001 From: Mygod Date: Sat, 13 Jan 2018 16:08:44 +0800 Subject: [PATCH] Add support for WPS in repeater --- .../be/mygod/vpnhotspot/RepeaterFragment.kt | 31 ++++++++++++++++--- .../be/mygod/vpnhotspot/RepeaterService.kt | 30 ++++++++++++++++++ mobile/src/main/res/layout/dialog_wps.xml | 17 ++++++++++ .../src/main/res/layout/fragment_repeater.xml | 4 +-- mobile/src/main/res/menu/repeater.xml | 7 +++++ 5 files changed, 81 insertions(+), 8 deletions(-) create mode 100644 mobile/src/main/res/layout/dialog_wps.xml create mode 100644 mobile/src/main/res/menu/repeater.xml diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterFragment.kt index 42f0c46a..69e3852d 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterFragment.kt @@ -13,16 +13,18 @@ import android.os.IBinder import android.support.v4.app.Fragment import android.support.v4.content.ContextCompat import android.support.v4.content.LocalBroadcastManager +import android.support.v7.app.AlertDialog +import android.support.v7.app.AppCompatDialog import android.support.v7.widget.DefaultItemAnimator import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup +import android.support.v7.widget.Toolbar +import android.view.* +import android.widget.EditText import be.mygod.vpnhotspot.databinding.FragmentRepeaterBinding import be.mygod.vpnhotspot.databinding.ListitemClientBinding -class RepeaterFragment : Fragment(), ServiceConnection { +class RepeaterFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClickListener { inner class Data : BaseObservable() { val switchEnabled: Boolean @Bindable get() = when (binder?.service?.status) { @@ -71,7 +73,7 @@ class RepeaterFragment : Fragment(), ServiceConnection { fun fetchClients() { val binder = binder - if (binder?.service?.status == RepeaterService.Status.ACTIVE) { + if (binder?.active == true) { owner = binder.service.group.owner clients = binder.service.group.clientList arpCache = NetUtils.arp(binder.service.routing?.downstream) @@ -113,6 +115,8 @@ class RepeaterFragment : Fragment(), ServiceConnection { binding.clients.itemAnimator = animator binding.clients.adapter = adapter binding.swipeRefresher.setOnRefreshListener { adapter.fetchClients() } + binding.toolbar.inflateMenu(R.menu.repeater) + binding.toolbar.setOnMenuItemClickListener(this) return binding.root } @@ -143,4 +147,21 @@ class RepeaterFragment : Fragment(), ServiceConnection { LocalBroadcastManager.getInstance(context!!).unregisterReceiver(data.statusListener) data.onStatusChanged() } + + override fun onMenuItemClick(item: MenuItem) = when (item.itemId) { + R.id.wps -> if (binder?.active == true) { + val dialog = AlertDialog.Builder(context!!) + .setTitle("Enter PIN") + .setView(R.layout.dialog_wps) + .setPositiveButton(android.R.string.ok, { dialog, _ -> binder?.startWps((dialog as AppCompatDialog) + .findViewById(android.R.id.edit)!!.text.toString()) }) + .setNegativeButton(android.R.string.cancel, null) + .setNeutralButton("Push Button", { _, _ -> binder?.startWps(null) }) + .create() + dialog.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) + dialog.show() + true + } else false + else -> false + } } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt index 79cc9cb8..5cc695c4 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt @@ -5,6 +5,7 @@ import android.app.Service import android.content.Context import android.content.Intent import android.net.NetworkInfo +import android.net.wifi.WpsInfo import android.net.wifi.p2p.WifiP2pGroup import android.net.wifi.p2p.WifiP2pInfo import android.net.wifi.p2p.WifiP2pManager @@ -37,6 +38,18 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnListener.C * https://android.googlesource.com/platform/frameworks/base.git/+/220871a/core/java/android/net/NetworkInfo.java#415 */ private val patternNetworkInfo = "^mNetworkInfo .* (isA|a)vailable: (true|false)".toPattern(Pattern.MULTILINE) + + /** + * Available since Android 4.3. + * + * Source: https://android.googlesource.com/platform/frameworks/base/+/android-4.3_r0.9/wifi/java/android/net/wifi/p2p/WifiP2pManager.java#958 + */ + private val startWpsMethod = WifiP2pManager::class.java.getDeclaredMethod("startWps", + WifiP2pManager.Channel::class.java, WpsInfo::class.java, WifiP2pManager.ActionListener::class.java) + private fun WifiP2pManager.startWps(c: WifiP2pManager.Channel, wps: WpsInfo, + listener: WifiP2pManager.ActionListener) { + startWpsMethod.invoke(this, c, wps, listener) + } } enum class Status { @@ -46,6 +59,23 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnListener.C inner class HotspotBinder : Binder() { val service get() = this@RepeaterService var data: RepeaterFragment.Data? = null + val active get() = status == Status.ACTIVE + + fun startWps(pin: String? = null) { + if (status != Status.ACTIVE) return + val wps = WpsInfo() + if (pin == null) wps.setup = WpsInfo.PBC else { + wps.setup = WpsInfo.KEYPAD + wps.pin = pin + } + p2pManager.startWps(channel, wps, object : WifiP2pManager.ActionListener { + override fun onSuccess() = Toast.makeText(this@RepeaterService, + if (pin == null) "Please use WPS push button within the next 2 minutes to connect your device." + else "PIN registered.", Toast.LENGTH_SHORT).show() + override fun onFailure(reason: Int) = Toast.makeText(this@RepeaterService, + "Failed to start WPS (reason: ${formatReason(reason)})", Toast.LENGTH_SHORT).show() + }) + } fun shutdown() { if (status == Status.ACTIVE) removeGroup() diff --git a/mobile/src/main/res/layout/dialog_wps.xml b/mobile/src/main/res/layout/dialog_wps.xml new file mode 100644 index 00000000..e3a7eaf8 --- /dev/null +++ b/mobile/src/main/res/layout/dialog_wps.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/mobile/src/main/res/layout/fragment_repeater.xml b/mobile/src/main/res/layout/fragment_repeater.xml index 9e2d4f5f..b99394ce 100644 --- a/mobile/src/main/res/layout/fragment_repeater.xml +++ b/mobile/src/main/res/layout/fragment_repeater.xml @@ -27,10 +27,8 @@ android:enabled="@{data.switchEnabled}" android:checked="@{data.serviceStarted}" android:onCheckedChanged="@{(_, checked) -> data.setServiceStarted(checked)}" - android:paddingEnd="8dp" android:text="@string/app_name" - android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title" - tools:ignore="RtlSymmetry"/> + android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title"/> + + + + \ No newline at end of file