From 826f601301c8584749584c9cb10864fdfd09844c Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 3 Jan 2018 22:58:45 +0800 Subject: [PATCH] Add settings --- mobile/build.gradle | 4 +- mobile/src/main/AndroidManifest.xml | 9 +- .../src/main/java/be/mygod/vpnhotspot/App.kt | 8 ++ .../be/mygod/vpnhotspot/HotspotService.kt | 109 ++++++++++-------- .../java/be/mygod/vpnhotspot/MainActivity.kt | 48 +++++--- .../be/mygod/vpnhotspot/SettingsActivity.kt | 14 +++ .../be/mygod/vpnhotspot/SettingsFragment.kt | 82 +++++++++++++ .../main/java/be/mygod/vpnhotspot/Utils.kt | 9 +- .../main/res/drawable/ic_action_settings.xml | 9 ++ .../main/res/drawable/ic_navigation_close.xml | 9 ++ .../{main_activity.xml => activity_main.xml} | 4 +- .../src/main/res/layout/activity_settings.xml | 26 +++++ .../{client.xml => listitem_client.xml} | 2 + mobile/src/main/res/menu/main.xml | 9 ++ mobile/src/main/res/values/strings.xml | 1 + mobile/src/main/res/values/styles.xml | 4 +- mobile/src/main/res/xml/pref_settings.xml | 41 +++++++ 17 files changed, 313 insertions(+), 75 deletions(-) create mode 100644 mobile/src/main/java/be/mygod/vpnhotspot/SettingsActivity.kt create mode 100644 mobile/src/main/java/be/mygod/vpnhotspot/SettingsFragment.kt create mode 100644 mobile/src/main/res/drawable/ic_action_settings.xml create mode 100644 mobile/src/main/res/drawable/ic_navigation_close.xml rename mobile/src/main/res/layout/{main_activity.xml => activity_main.xml} (96%) create mode 100644 mobile/src/main/res/layout/activity_settings.xml rename mobile/src/main/res/layout/{client.xml => listitem_client.xml} (92%) create mode 100644 mobile/src/main/res/menu/main.xml create mode 100644 mobile/src/main/res/xml/pref_settings.xml diff --git a/mobile/build.gradle b/mobile/build.gradle index 977dd270..1f9239dc 100644 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -1,6 +1,5 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' android { @@ -13,7 +12,6 @@ android { versionCode 1 versionName "0.0.1" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - vectorDrawables.useSupportLibrary true } buildTypes { debug { @@ -29,6 +27,8 @@ android { } dependencies { + implementation 'com.android.support.constraint:constraint-layout:1.0.2' + implementation 'com.android.support:design:27.0.2' kapt "com.android.databinding:compiler:$androidPluginVersion" implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "com.android.support:customtabs:$supportLibraryVersion" diff --git a/mobile/src/main/AndroidManifest.xml b/mobile/src/main/AndroidManifest.xml index 11e2aaeb..6173b525 100644 --- a/mobile/src/main/AndroidManifest.xml +++ b/mobile/src/main/AndroidManifest.xml @@ -21,9 +21,12 @@ - + + + - + \ No newline at end of file diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/App.kt b/mobile/src/main/java/be/mygod/vpnhotspot/App.kt index a482328d..6facaf52 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/App.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/App.kt @@ -4,12 +4,20 @@ import android.app.Application import android.app.NotificationChannel import android.app.NotificationManager import android.os.Build +import android.preference.PreferenceManager class App : Application() { + companion object { + lateinit var app: App + } + override fun onCreate() { super.onCreate() + app = this if (Build.VERSION.SDK_INT >= 26) getSystemService(NotificationManager::class.java) .createNotificationChannel(NotificationChannel(HotspotService.CHANNEL, "Hotspot Service", NotificationManager.IMPORTANCE_LOW)) } + + val pref by lazy { PreferenceManager.getDefaultSharedPreferences(this) } } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt index 735ad334..f9cf8f04 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/HotspotService.kt @@ -2,22 +2,26 @@ package be.mygod.vpnhotspot import android.app.PendingIntent import android.app.Service -import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.net.NetworkInfo -import android.net.wifi.p2p.* +import android.net.wifi.p2p.WifiP2pGroup +import android.net.wifi.p2p.WifiP2pInfo +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.support.v4.content.LocalBroadcastManager import android.util.Log import android.widget.Toast +import be.mygod.vpnhotspot.App.Companion.app import java.net.InetAddress class HotspotService : Service(), WifiP2pManager.ChannelListener { companion object { const val CHANNEL = "hotspot" + const val STATUS_CHANGED = "be.mygod.vpnhotspot.HotspotService.STATUS_CHANGED" private const val TAG = "HotspotService" } @@ -27,7 +31,6 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { inner class HotspotBinder : Binder() { val service get() = this@HotspotService - val status get() = this@HotspotService.status var data: MainActivity.Data? = null fun shutdown() { @@ -35,9 +38,9 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { override fun onSuccess() = clean() override fun onFailure(reason: Int) { if (reason == WifiP2pManager.BUSY) clean() else { // assuming it's already gone - Toast.makeText(this@HotspotService, "Failed to remove P2P group (reason: $reason)", + Toast.makeText(this@HotspotService, "Failed to remove P2P group (${formatReason(reason)})", Toast.LENGTH_SHORT).show() - binder.data?.onStatusChanged() + LocalBroadcastManager.getInstance(this@HotspotService).sendBroadcast(Intent(STATUS_CHANGED)) } } }) @@ -52,43 +55,41 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { private set private val binder = HotspotBinder() private var receiverRegistered = false - private val receiver: BroadcastReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - when (intent.action) { - WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION -> - if (intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, 0) == - WifiP2pManager.WIFI_P2P_STATE_DISABLED) clean() // group may be enabled by other apps - WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION -> { - val info = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO) - val net = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO) - val group = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP) - hostAddress = info.groupOwnerAddress - val downstream = group.`interface` - if (net.isConnected && downstream != null && this@HotspotService.downstream == null) { - this@HotspotService.downstream = downstream - if (noisySu("echo 1 >/proc/sys/net/ipv4/ip_forward", - "ip route add default dev $upstream scope link table 62", - "ip route add $route dev $downstream scope link table 62", - "ip route add broadcast 255.255.255.255 dev $downstream scope link table 62", - "ip rule add from $route lookup 62", - "iptables -N vpnhotspot_fwd", - "iptables -A vpnhotspot_fwd -i $upstream -o $downstream -m state --state ESTABLISHED,RELATED -j ACCEPT", - "iptables -A vpnhotspot_fwd -i $downstream -o $upstream -j ACCEPT", - "iptables -I FORWARD -j vpnhotspot_fwd", - "iptables -t nat -A PREROUTING -i $downstream -p tcp --dport 53 -j DNAT --to-destination $dns", - "iptables -t nat -A PREROUTING -i $downstream -p udp --dport 53 -j DNAT --to-destination $dns")) { - doStart(group) - } else startFailure("Something went wrong, please check logcat.") - } - this@HotspotService.group = group - binder.data?.onGroupChanged() - showNotification(group) - Log.d(TAG, "${intent.action}: $info, $net, $group") - } - WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION -> { - val info = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO) - Log.d(TAG, "${intent.action}: $info") + private val receiver = broadcastReceiver { _, intent -> + when (intent.action) { + WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION -> + if (intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, 0) == + WifiP2pManager.WIFI_P2P_STATE_DISABLED) clean() // group may be enabled by other apps + WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION -> { + val info = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO) + val net = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO) + val group = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP) + hostAddress = info.groupOwnerAddress + val downstream = group.`interface` + if (net.isConnected && downstream != null && this@HotspotService.downstream == null) { + this@HotspotService.downstream = downstream + if (noisySu("echo 1 >/proc/sys/net/ipv4/ip_forward", + "ip route add default dev $upstream scope link table 62", + "ip route add $route dev $downstream scope link table 62", + "ip route add broadcast 255.255.255.255 dev $downstream scope link table 62", + "ip rule add from $route lookup 62", + "iptables -N vpnhotspot_fwd", + "iptables -A vpnhotspot_fwd -i $upstream -o $downstream -m state --state ESTABLISHED,RELATED -j ACCEPT", + "iptables -A vpnhotspot_fwd -i $downstream -o $upstream -j ACCEPT", + "iptables -I FORWARD -j vpnhotspot_fwd", + "iptables -t nat -A PREROUTING -i $downstream -p tcp --dport 53 -j DNAT --to-destination $dns", + "iptables -t nat -A PREROUTING -i $downstream -p udp --dport 53 -j DNAT --to-destination $dns")) { + doStart(group) + } else startFailure("Something went wrong, please check logcat.") } + this@HotspotService.group = group + binder.data?.onGroupChanged() + showNotification(group) + Log.d(TAG, "${intent.action}: $info, $net, $group") + } + WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION -> { + val info = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO) + Log.d(TAG, "${intent.action}: $info") } } } @@ -96,16 +97,25 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { // TODO: do something to these hardcoded strings var downstream: String? = null private set - private val upstream = "tun0" - private val route = "192.168.49.0/24" - private val dns = "8.8.8.8:53" + private val upstream get() = app.pref.getString("service.upstream", "tun0") + private val route get() = app.pref.getString("service.route", "192.168.49.0/24") + private val dns get() = app.pref.getString("service.dns", "8.8.8.8:53") var status = Status.IDLE private set(value) { + if (field == value) return field = value - binder.data?.onStatusChanged() + LocalBroadcastManager.getInstance(this).sendBroadcast(Intent(STATUS_CHANGED)) } + private fun formatReason(reason: Int) = when (reason) { + WifiP2pManager.ERROR -> "ERROR" + WifiP2pManager.P2P_UNSUPPORTED -> "P2P_UNSUPPORTED" + WifiP2pManager.BUSY -> "BUSY" + WifiP2pManager.NO_SERVICE_REQUESTS -> "NO_SERVICE_REQUESTS" + else -> "unknown reason: $reason" + } + override fun onBind(intent: Intent) = binder override fun onCreate() { @@ -122,7 +132,7 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { if (status != Status.IDLE) return START_NOT_STICKY status = Status.STARTING if (!receiverRegistered) { - registerReceiver(receiver, createIntentFilter( + registerReceiver(receiver, intentFilter( WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION, WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION, WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)) @@ -137,8 +147,9 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { 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() + Toast.makeText(this@HotspotService, + "Failed to remove old P2P group (${formatReason(reason)})", Toast.LENGTH_SHORT) + .show() } }) } @@ -153,7 +164,7 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener { clean() } private fun doStart() = p2pManager.createGroup(channel, object : WifiP2pManager.ActionListener { - override fun onFailure(reason: Int) = startFailure("Failed to create P2P group (reason: $reason)") + override fun onFailure(reason: Int) = startFailure("Failed to create P2P group (${formatReason(reason)})") override fun onSuccess() { } // wait for WIFI_P2P_CONNECTION_CHANGED_ACTION to fire }) private fun doStart(group: WifiP2pGroup) { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt b/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt index a11b20aa..7d74203f 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/MainActivity.kt @@ -1,9 +1,6 @@ package be.mygod.vpnhotspot -import android.content.ComponentName -import android.content.Context -import android.content.Intent -import android.content.ServiceConnection +import android.content.* import android.databinding.BaseObservable import android.databinding.Bindable import android.databinding.DataBindingUtil @@ -11,32 +8,35 @@ import android.net.wifi.p2p.WifiP2pDevice import android.os.Bundle import android.os.IBinder import android.support.v4.content.ContextCompat +import android.support.v4.content.LocalBroadcastManager import android.support.v7.app.AppCompatActivity import android.support.v7.widget.DefaultItemAnimator import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView +import android.support.v7.widget.Toolbar import android.view.LayoutInflater +import android.view.MenuItem import android.view.ViewGroup -import be.mygod.vpnhotspot.databinding.ClientBinding -import be.mygod.vpnhotspot.databinding.MainActivityBinding +import be.mygod.vpnhotspot.databinding.ActivityMainBinding +import be.mygod.vpnhotspot.databinding.ListitemClientBinding -class MainActivity : AppCompatActivity(), ServiceConnection { +class MainActivity : AppCompatActivity(), ServiceConnection, Toolbar.OnMenuItemClickListener { inner class Data : BaseObservable() { val switchEnabled: Boolean - @Bindable get() = when (binder?.status) { + @Bindable get() = when (binder?.service?.status) { HotspotService.Status.IDLE -> true HotspotService.Status.ACTIVE -> true else -> false } var serviceStarted: Boolean - @Bindable get() = when (binder?.status) { + @Bindable get() = when (binder?.service?.status) { HotspotService.Status.STARTING -> true HotspotService.Status.ACTIVE -> true else -> false } set(value) { val binder = binder - when (binder?.status) { + when (binder?.service?.status) { HotspotService.Status.IDLE -> if (value) ContextCompat.startForegroundService(this@MainActivity, Intent(this@MainActivity, HotspotService::class.java)) @@ -44,7 +44,7 @@ class MainActivity : AppCompatActivity(), ServiceConnection { } } - val running get() = binder?.status == HotspotService.Status.ACTIVE + val running get() = binder?.service?.status == HotspotService.Status.ACTIVE val ssid: String @Bindable get() = if (running) binder!!.service.group.networkName else "" val password: String @Bindable get() = if (running) binder!!.service.group.passphrase else "" @@ -58,17 +58,19 @@ class MainActivity : AppCompatActivity(), ServiceConnection { notifyPropertyChanged(BR.password) adapter.fetchClients() } + + val statusListener = broadcastReceiver { _, _ -> onStatusChanged() } } - class ClientViewHolder(val binding: ClientBinding) : RecyclerView.ViewHolder(binding.root) + class ClientViewHolder(val binding: ListitemClientBinding) : RecyclerView.ViewHolder(binding.root) inner class ClientAdapter : RecyclerView.Adapter() { private var owner: WifiP2pDevice? = null private lateinit var clients: MutableCollection private lateinit var arpCache: ArpCache fun fetchClients() { - val binder = binder!! if (data.running) { + val binder = binder!! owner = binder.service.group.owner clients = binder.service.group.clientList arpCache = ArpCache(binder.service.downstream) @@ -77,7 +79,7 @@ class MainActivity : AppCompatActivity(), ServiceConnection { } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = - ClientViewHolder(ClientBinding.inflate(LayoutInflater.from(parent.context))) + ClientViewHolder(ListitemClientBinding.inflate(LayoutInflater.from(parent.context))) override fun onBindViewHolder(holder: ClientViewHolder, position: Int) { val device = when (position) { @@ -95,20 +97,30 @@ class MainActivity : AppCompatActivity(), ServiceConnection { override fun getItemCount() = if (owner == null) 0 else 1 + clients.size } - private lateinit var binding: MainActivityBinding + private lateinit var binding: ActivityMainBinding private val data = Data() private val adapter = ClientAdapter() private var binder: HotspotService.HotspotBinder? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - binding = DataBindingUtil.setContentView(this, R.layout.main_activity) + binding = DataBindingUtil.setContentView(this, R.layout.activity_main) binding.data = data binding.clients.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) val animator = DefaultItemAnimator() animator.supportsChangeAnimations = false // prevent fading-in/out when rebinding binding.clients.itemAnimator = animator binding.clients.adapter = adapter + binding.toolbar.inflateMenu(R.menu.main) + binding.toolbar.setOnMenuItemClickListener(this) + } + + override fun onMenuItemClick(item: MenuItem): Boolean = when (item.itemId) { + R.id.settings -> { + startActivity(Intent(this, SettingsActivity::class.java)) + true + } + else -> false } override fun onStart() { @@ -117,6 +129,7 @@ class MainActivity : AppCompatActivity(), ServiceConnection { } override fun onStop() { + onServiceDisconnected(null) unbindService(this) super.onStop() } @@ -126,11 +139,14 @@ class MainActivity : AppCompatActivity(), ServiceConnection { binder.data = data this.binder = binder data.onStatusChanged() + LocalBroadcastManager.getInstance(this) + .registerReceiver(data.statusListener, intentFilter(HotspotService.STATUS_CHANGED)) } override fun onServiceDisconnected(name: ComponentName?) { binder?.data = null binder = null + LocalBroadcastManager.getInstance(this).unregisterReceiver(data.statusListener) data.onStatusChanged() } } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/SettingsActivity.kt b/mobile/src/main/java/be/mygod/vpnhotspot/SettingsActivity.kt new file mode 100644 index 00000000..3d62bd66 --- /dev/null +++ b/mobile/src/main/java/be/mygod/vpnhotspot/SettingsActivity.kt @@ -0,0 +1,14 @@ +package be.mygod.vpnhotspot + +import android.databinding.DataBindingUtil +import android.os.Bundle +import android.support.v7.app.AppCompatActivity +import be.mygod.vpnhotspot.databinding.ActivitySettingsBinding + +class SettingsActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + DataBindingUtil.setContentView(this, R.layout.activity_settings) + .toolbar.setNavigationOnClickListener({ finish() }) + } +} diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/SettingsFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/SettingsFragment.kt new file mode 100644 index 00000000..b11202d0 --- /dev/null +++ b/mobile/src/main/java/be/mygod/vpnhotspot/SettingsFragment.kt @@ -0,0 +1,82 @@ +package be.mygod.vpnhotspot + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.net.Uri +import android.os.Bundle +import android.os.IBinder +import android.support.customtabs.CustomTabsIntent +import android.support.v4.content.ContextCompat +import android.support.v4.content.LocalBroadcastManager +import android.support.v7.preference.Preference +import com.takisoft.fix.support.v7.preference.PreferenceFragmentCompatDividers + +class SettingsFragment : PreferenceFragmentCompatDividers(), ServiceConnection { + private lateinit var service: Preference + private var binder: HotspotService.HotspotBinder? = null + private val statusListener = broadcastReceiver { _, _ -> onStatusChanged() } + private val customTabsIntent by lazy { + CustomTabsIntent.Builder().setToolbarColor(ContextCompat.getColor(activity!!, R.color.colorPrimary)).build() + } + + override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) { + addPreferencesFromResource(R.xml.pref_settings) + service = findPreference("service") + findPreference("service.clean").setOnPreferenceClickListener { + noisySu("iptables -t nat -F PREROUTING", + "while iptables -D FORWARD -j vpnhotspot_fwd; do done", + "iptables -F vpnhotspot_fwd", + "iptables -X vpnhotspot_fwd", + "ip rule del lookup 62", + "ip route flush table 62") + true + } + findPreference("misc.logcat").setOnPreferenceClickListener { + val intent = Intent(Intent.ACTION_SEND) + .setType("text/plain") + .putExtra(Intent.EXTRA_TEXT, Runtime.getRuntime().exec(arrayOf("logcat", "-d")) + .inputStream.bufferedReader().use { it.readText() }) + startActivity(Intent.createChooser(intent, getString(R.string.abc_shareactionprovider_share_with))) + true + } + findPreference("misc.source").setOnPreferenceClickListener { + customTabsIntent.launchUrl(activity, Uri.parse("https://github.com/Mygod/VPNHotspot")) + true + } + findPreference("misc.donate").setOnPreferenceClickListener { + customTabsIntent.launchUrl(activity, Uri.parse("https://mygod.be/donate/")) + true + } + } + + override fun onStart() { + super.onStart() + val activity = activity!! + activity.bindService(Intent(activity, HotspotService::class.java), this, Context.BIND_AUTO_CREATE) + } + + override fun onStop() { + onServiceDisconnected(null) + activity!!.unbindService(this) + super.onStop() + } + + override fun onServiceConnected(name: ComponentName?, service: IBinder?) { + binder = service as HotspotService.HotspotBinder + onStatusChanged() + LocalBroadcastManager.getInstance(activity!!) + .registerReceiver(statusListener, intentFilter(HotspotService.STATUS_CHANGED)) + } + + override fun onServiceDisconnected(name: ComponentName?) { + LocalBroadcastManager.getInstance(activity!!).unregisterReceiver(statusListener) + binder = null + service.isEnabled = false + } + + private fun onStatusChanged() { + service.isEnabled = binder!!.service.status == HotspotService.Status.IDLE + } +} diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/Utils.kt b/mobile/src/main/java/be/mygod/vpnhotspot/Utils.kt index a96ccd46..89b267fa 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/Utils.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/Utils.kt @@ -1,9 +1,16 @@ package be.mygod.vpnhotspot +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent import android.content.IntentFilter import android.util.Log -fun createIntentFilter(vararg actions: String): IntentFilter { +fun broadcastReceiver(receiver: (Context, Intent) -> Unit) = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) = receiver(context, intent) +} + +fun intentFilter(vararg actions: String): IntentFilter { val result = IntentFilter() actions.forEach { result.addAction(it) } return result diff --git a/mobile/src/main/res/drawable/ic_action_settings.xml b/mobile/src/main/res/drawable/ic_action_settings.xml new file mode 100644 index 00000000..4f24c6a6 --- /dev/null +++ b/mobile/src/main/res/drawable/ic_action_settings.xml @@ -0,0 +1,9 @@ + + + diff --git a/mobile/src/main/res/drawable/ic_navigation_close.xml b/mobile/src/main/res/drawable/ic_navigation_close.xml new file mode 100644 index 00000000..0a244b99 --- /dev/null +++ b/mobile/src/main/res/drawable/ic_navigation_close.xml @@ -0,0 +1,9 @@ + + + diff --git a/mobile/src/main/res/layout/main_activity.xml b/mobile/src/main/res/layout/activity_main.xml similarity index 96% rename from mobile/src/main/res/layout/main_activity.xml rename to mobile/src/main/res/layout/activity_main.xml index 24981173..72e0833b 100644 --- a/mobile/src/main/res/layout/main_activity.xml +++ b/mobile/src/main/res/layout/activity_main.xml @@ -58,6 +58,7 @@ android:layout_column="2" android:layout_row="0" android:text="@{data.ssid}" + android:textIsSelectable="true" tools:text="DIRECT-rAnd0m"/> @@ -101,6 +103,6 @@ android:paddingTop="8dp" android:clipToPadding="false" android:scrollbars="vertical" - tools:listitem="@layout/client"/> + tools:listitem="@layout/listitem_client"/> diff --git a/mobile/src/main/res/layout/activity_settings.xml b/mobile/src/main/res/layout/activity_settings.xml new file mode 100644 index 00000000..8285794c --- /dev/null +++ b/mobile/src/main/res/layout/activity_settings.xml @@ -0,0 +1,26 @@ + + + + + + + \ No newline at end of file diff --git a/mobile/src/main/res/layout/client.xml b/mobile/src/main/res/layout/listitem_client.xml similarity index 92% rename from mobile/src/main/res/layout/client.xml rename to mobile/src/main/res/layout/listitem_client.xml index 44dd7204..00e71e85 100644 --- a/mobile/src/main/res/layout/client.xml +++ b/mobile/src/main/res/layout/listitem_client.xml @@ -21,6 +21,7 @@ android:layout_height="wrap_content" android:text="@{device.deviceAddress}" android:textAppearance="@style/TextAppearance.AppCompat.Subhead" + android:textIsSelectable="true" tools:text="xx:xx:xx:xx:xx:xx"/> diff --git a/mobile/src/main/res/menu/main.xml b/mobile/src/main/res/menu/main.xml new file mode 100644 index 00000000..279445c5 --- /dev/null +++ b/mobile/src/main/res/menu/main.xml @@ -0,0 +1,9 @@ + + + + diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml index b0fb706f..ce3658d4 100644 --- a/mobile/src/main/res/values/strings.xml +++ b/mobile/src/main/res/values/strings.xml @@ -1,3 +1,4 @@ VPN Hotspot + Settings diff --git a/mobile/src/main/res/values/styles.xml b/mobile/src/main/res/values/styles.xml index 0eb88fe3..77806e72 100644 --- a/mobile/src/main/res/values/styles.xml +++ b/mobile/src/main/res/values/styles.xml @@ -1,8 +1,6 @@ - -