From 4e1f7c9c400868c01a2c756eea23818778cfe1ac Mon Sep 17 00:00:00 2001 From: Mygod Date: Tue, 12 Jul 2022 10:18:52 -0400 Subject: [PATCH] Support new permission in Tiramisu --- README.md | 13 ++++---- mobile/src/google/AndroidManifest.xml | 9 +++++- .../src/main/java/be/mygod/vpnhotspot/App.kt | 26 ++++++++++++++++ .../be/mygod/vpnhotspot/RepeaterService.kt | 4 +-- .../manage/LocalOnlyHotspotManager.kt | 30 +++++-------------- .../vpnhotspot/manage/RepeaterManager.kt | 4 ++- .../vpnhotspot/manage/TetheringFragment.kt | 3 +- mobile/src/main/res/values-it/strings.xml | 2 +- mobile/src/main/res/values-zh-rCN/strings.xml | 2 +- mobile/src/main/res/values-zh-rTW/strings.xml | 2 +- mobile/src/main/res/values/strings.xml | 2 +- 11 files changed, 59 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 93d14036..45f168d3 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,13 @@ Connecting things to your VPN made simple. Share your VPN connection over hotspot or repeater. (**root required**) -| Release channel | [GitHub (recommended)](https://github.com/Mygod/VPNHotspot/releases) | [Google Play](https://play.google.com/store/apps/details?id=be.mygod.vpnhotspot) ([beta](https://play.google.com/apps/testing/be.mygod.vpnhotspot)) | -| --- | :---: | :---: | -| Monitor connected clients without root | ✓ | Up to Android 10 | -| Auto update | Email updates via watching releases | ✓ | -| In-app update channel | GitHub | Google Play | -| [Sponsor/Donation](https://github.com/sponsors/Mygod) | ✓ | Google Play In-App Purchases only | +| Release channel | [GitHub (recommended)](https://github.com/Mygod/VPNHotspot/releases) | [Google Play](https://play.google.com/store/apps/details?id=be.mygod.vpnhotspot) ([beta](https://play.google.com/apps/testing/be.mygod.vpnhotspot)) | +|---------------------------------------------------------|:--------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------------------------------------------------------:| +| Monitor connected clients without root | ✓ | Up to Android 10 | +| Use repeater/temporary hotspot without location enabled | Up to Android 10/9 | Up to Android 10/9 or Android 13+ | +| Auto update | Email updates via watching releases | ✓ | +| In-app update channel | GitHub | Google Play | +| [Sponsor/Donation](https://github.com/sponsors/Mygod) | ✓ | Google Play In-App Purchases only | This app is useful for: diff --git a/mobile/src/google/AndroidManifest.xml b/mobile/src/google/AndroidManifest.xml index 0c4ac9c4..62479015 100644 --- a/mobile/src/google/AndroidManifest.xml +++ b/mobile/src/google/AndroidManifest.xml @@ -1,5 +1,12 @@ - + + + + + diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/App.kt b/mobile/src/main/java/be/mygod/vpnhotspot/App.kt index 8a74252b..9856e2c9 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/App.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/App.kt @@ -2,11 +2,16 @@ package be.mygod.vpnhotspot import android.annotation.SuppressLint import android.app.Application +import android.content.ActivityNotFoundException import android.content.ClipboardManager +import android.content.Context +import android.content.Intent import android.content.res.Configuration import android.location.LocationManager import android.os.Build +import android.provider.Settings import android.util.Log +import android.widget.Toast import androidx.annotation.Size import androidx.browser.customtabs.CustomTabColorSchemeParams import androidx.browser.customtabs.CustomTabsIntent @@ -19,6 +24,7 @@ import be.mygod.vpnhotspot.room.AppDatabase import be.mygod.vpnhotspot.root.RootManager import be.mygod.vpnhotspot.util.DeviceStorageApp import be.mygod.vpnhotspot.util.Services +import be.mygod.vpnhotspot.widget.SmartSnackbar import com.google.firebase.analytics.ktx.ParametersBuilder import com.google.firebase.analytics.ktx.analytics import com.google.firebase.crashlytics.FirebaseCrashlytics @@ -104,6 +110,26 @@ class App : Application() { Firebase.analytics.logEvent(event, builder.bundle) } + /** + * LOH also requires location to be turned on. So does p2p for some reason. Source: + * https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/53e0284/service/java/com/android/server/wifi/WifiServiceImpl.java#1204 + * https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/53e0284/service/java/com/android/server/wifi/WifiSettingsStore.java#228 + */ + inline fun startServiceWithLocation(context: Context) { + if (BuildConfig.TARGET_SDK >= 33 && Build.VERSION.SDK_INT >= 33 || if (Build.VERSION.SDK_INT >= 28) { + location?.isLocationEnabled == true + } else @Suppress("DEPRECATION") { + Settings.Secure.getInt(context.contentResolver, Settings.Secure.LOCATION_MODE, + Settings.Secure.LOCATION_MODE_OFF) != Settings.Secure.LOCATION_MODE_OFF + }) ContextCompat.startForegroundService(context, Intent(context, T::class.java)) else try { + context.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)) + Toast.makeText(context, R.string.tethering_location_off, Toast.LENGTH_LONG).show() + } catch (e: ActivityNotFoundException) { + app.logEvent("location_settings") { param("message", e.toString()) } + SmartSnackbar.make(R.string.tethering_location_off).show() + } + } + lateinit var deviceStorage: Application val english by lazy { createConfigurationContext(Configuration(resources.configuration).apply { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt index c689d6f2..8c44a15e 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt @@ -364,7 +364,7 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene launch { val filter = intentFilter(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION, WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION) - if (Build.VERSION.SDK_INT >= 30) filter.addAction(LocationManager.MODE_CHANGED_ACTION) + if (Build.VERSION.SDK_INT in 30 until 33) filter.addAction(LocationManager.MODE_CHANGED_ACTION) registerReceiver(receiver, filter) receiverRegistered = true val group = p2pManager.requestGroupInfo(channel) @@ -397,7 +397,7 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene override fun onSuccess() { // wait for WIFI_P2P_CONNECTION_CHANGED_ACTION to fire to go to step 3 // in order for this to happen, we need to make sure that the callbacks are firing - if (Build.VERSION.SDK_INT >= 30) onLocationModeChanged(app.location?.isLocationEnabled == true) + if (Build.VERSION.SDK_INT in 30 until 33) onLocationModeChanged(app.location?.isLocationEnabled == true) } } val channel = channel ?: return listener.onFailure(WifiP2pManager.BUSY) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/manage/LocalOnlyHotspotManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/manage/LocalOnlyHotspotManager.kt index 62db344d..03ddb23e 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/LocalOnlyHotspotManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/LocalOnlyHotspotManager.kt @@ -4,26 +4,26 @@ import android.Manifest import android.content.* import android.os.Build import android.os.IBinder -import android.provider.Settings import android.view.View -import android.widget.Toast import androidx.annotation.RequiresApi import androidx.recyclerview.widget.RecyclerView import be.mygod.vpnhotspot.App.Companion.app +import be.mygod.vpnhotspot.BuildConfig import be.mygod.vpnhotspot.LocalOnlyHotspotService import be.mygod.vpnhotspot.R import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding import be.mygod.vpnhotspot.util.ServiceForegroundConnector import be.mygod.vpnhotspot.util.formatAddresses -import be.mygod.vpnhotspot.widget.SmartSnackbar import java.net.NetworkInterface @RequiresApi(26) class LocalOnlyHotspotManager(private val parent: TetheringFragment) : Manager(), ServiceConnection { companion object { - val permission = if (Build.VERSION.SDK_INT >= 29) { - Manifest.permission.ACCESS_FINE_LOCATION - } else Manifest.permission.ACCESS_COARSE_LOCATION + val permission = when { + BuildConfig.TARGET_SDK >= 33 && Build.VERSION.SDK_INT >= 33 -> Manifest.permission.NEARBY_WIFI_DEVICES + Build.VERSION.SDK_INT >= 29 -> Manifest.permission.ACCESS_FINE_LOCATION + else -> Manifest.permission.ACCESS_COARSE_LOCATION + } } class ViewHolder(val binding: ListitemInterfaceBinding) : RecyclerView.ViewHolder(binding.root), @@ -55,23 +55,7 @@ class LocalOnlyHotspotManager(private val parent: TetheringFragment) : Manager() ServiceForegroundConnector(parent, this, LocalOnlyHotspotService::class) } - /** - * LOH also requires location to be turned on. Source: - * https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/53e0284/service/java/com/android/server/wifi/WifiServiceImpl.java#1204 - * https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/53e0284/service/java/com/android/server/wifi/WifiSettingsStore.java#228 - */ - fun start(context: Context) { - if (if (Build.VERSION.SDK_INT < 28) @Suppress("DEPRECATION") { - Settings.Secure.getInt(context.contentResolver, Settings.Secure.LOCATION_MODE, - Settings.Secure.LOCATION_MODE_OFF) == Settings.Secure.LOCATION_MODE_OFF - } else app.location?.isLocationEnabled != true) try { - context.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)) - Toast.makeText(context, R.string.tethering_temp_hotspot_location, Toast.LENGTH_LONG).show() - } catch (e: ActivityNotFoundException) { - app.logEvent("location_settings") { param("message", e.toString()) } - SmartSnackbar.make(R.string.tethering_temp_hotspot_location).show() - } else context.startForegroundService(Intent(context, LocalOnlyHotspotService::class.java)) - } + fun start(context: Context) = app.startServiceWithLocation(context) override val type get() = VIEW_TYPE_LOCAL_ONLY_HOTSPOT private val data = Data() 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 82db1e60..faa4f29e 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt @@ -92,7 +92,9 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic when (binder?.service?.status) { RepeaterService.Status.IDLE -> if (Build.VERSION.SDK_INT < 29) parent.requireContext().let { context -> ContextCompat.startForegroundService(context, Intent(context, RepeaterService::class.java)) - } else parent.startRepeater.launch(Manifest.permission.ACCESS_FINE_LOCATION) + } else parent.startRepeater.launch(if (BuildConfig.TARGET_SDK >= 33 && Build.VERSION.SDK_INT >= 33) { + Manifest.permission.NEARBY_WIFI_DEVICES + } else Manifest.permission.ACCESS_FINE_LOCATION) RepeaterService.Status.ACTIVE -> binder.shutdown() else -> { } } 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 9f40b2c2..17d0d230 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetheringFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetheringFragment.kt @@ -24,6 +24,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import be.mygod.vpnhotspot.* +import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.databinding.FragmentTetheringBinding import be.mygod.vpnhotspot.net.TetherType import be.mygod.vpnhotspot.net.TetheringManager @@ -136,7 +137,7 @@ class TetheringFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClick @RequiresApi(29) val startRepeater = registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted -> - if (granted) requireActivity().startForegroundService(Intent(activity, RepeaterService::class.java)) else { + if (granted) app.startServiceWithLocation(requireContext()) else { Snackbar.make((activity as MainActivity).binding.fragmentHolder, R.string.repeater_missing_location_permissions, Snackbar.LENGTH_LONG).show() } diff --git a/mobile/src/main/res/values-it/strings.xml b/mobile/src/main/res/values-it/strings.xml index 223c86c3..64d0c3b7 100644 --- a/mobile/src/main/res/values-it/strings.xml +++ b/mobile/src/main/res/values-it/strings.xml @@ -38,7 +38,7 @@ Servizio non disponibile. Riprova dopo Hotspot Wi\u2011Fi temporaneo - L\'hotspot temporaneo richiede che la localizzazione sia attiva. + L\'hotspot temporaneo richiede che la localizzazione sia attiva. Avvio dell\'hotspot fallito (causa: %s) nessun canale errore generico diff --git a/mobile/src/main/res/values-zh-rCN/strings.xml b/mobile/src/main/res/values-zh-rCN/strings.xml index c17ea4a8..685f7586 100644 --- a/mobile/src/main/res/values-zh-rCN/strings.xml +++ b/mobile/src/main/res/values-zh-rCN/strings.xml @@ -34,7 +34,7 @@ 进入设置 临时 WLAN 热点 - 使用临时热点需要打开位置服务。 + 使用此功能需要打开位置服务。 打开热点失败 (原因:%s) 无频段 通用错误 diff --git a/mobile/src/main/res/values-zh-rTW/strings.xml b/mobile/src/main/res/values-zh-rTW/strings.xml index b8b29975..225ac273 100644 --- a/mobile/src/main/res/values-zh-rTW/strings.xml +++ b/mobile/src/main/res/values-zh-rTW/strings.xml @@ -44,7 +44,7 @@ 設定 臨時 Wi\u2011Fi 無線基地台 - 開啟臨時無線基地台須開啟定位 + 開啟須開啟定位 啟動無線基地台失敗 (原因:%s) 沒有頻道 一般錯誤 diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml index acad391d..24431a38 100644 --- a/mobile/src/main/res/values/strings.xml +++ b/mobile/src/main/res/values/strings.xml @@ -53,7 +53,7 @@ Configure Temporary Wi\u2011Fi hotspot - Temporary hotspot requires location to be turned on. + This feature requires location to be turned on. Failed to start hotspot (reason: %s) no channel generic error