diff --git a/README.md b/README.md index 4c84b6f0..dfe1db90 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,7 @@ Hidden whitelisted APIs: (same catch as above, however, things in this list are * (since API 24) [`Landroid/net/TetheringManager;->TETHERING_USB:I,system-api,test-api,whitelist`](https://android.googlesource.com/platform/prebuilts/runtime/+/4601d91/appcompat/hiddenapi-flags.csv#148944) * (since API 24) [`Landroid/net/TetheringManager;->TETHERING_WIFI:I,system-api,test-api,whitelist`](https://android.googlesource.com/platform/prebuilts/runtime/+/4601d91/appcompat/hiddenapi-flags.csv#148945) * [`Landroid/net/TetheringManager;->TETHER_ERROR_*:I,system-api,test-api,whitelist`](https://android.googlesource.com/platform/prebuilts/runtime/+/4601d91/appcompat/hiddenapi-flags.csv#148947) +* (since API 30) [`Landroid/net/TetheringManager;->TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION:I,system-api,test-api,whitelist`](https://android.googlesource.com/platform/prebuilts/runtime/+/4601d91/appcompat/hiddenapi-flags.csv#148954) * (since API 30) [`Landroid/net/TetheringManager;->TETHER_HARDWARE_OFFLOAD_FAILED:I,system-api,test-api,whitelist`](https://android.googlesource.com/platform/prebuilts/runtime/+/4601d91/appcompat/hiddenapi-flags.csv#148964) * (since API 30) [`Landroid/net/TetheringManager;->TETHER_HARDWARE_OFFLOAD_STARTED:I,system-api,test-api,whitelist`](https://android.googlesource.com/platform/prebuilts/runtime/+/4601d91/appcompat/hiddenapi-flags.csv#148965) * (since API 30) [`Landroid/net/TetheringManager;->TETHER_HARDWARE_OFFLOAD_STOPPED:I,system-api,test-api,whitelist`](https://android.googlesource.com/platform/prebuilts/runtime/+/4601d91/appcompat/hiddenapi-flags.csv#148966) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt index 92beeeef..a6cbb350 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt @@ -92,7 +92,13 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(), override fun onTetheringStarted() = data.notifyChange() override fun onTetheringFailed(error: Int?) { Timber.d("onTetheringFailed: $error") - error?.let { SmartSnackbar.make("$tetherType: ${TetheringManager.tetherErrorLookup(it)}").show() } + if (Build.VERSION.SDK_INT < 30 || error != TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION) { + error?.let { SmartSnackbar.make("$tetherType: ${TetheringManager.tetherErrorLookup(it)}").show() } + } else GlobalScope.launch(Dispatchers.Main.immediate) { + val context = parent.context ?: app + Toast.makeText(context, R.string.permission_missing, Toast.LENGTH_LONG).show() + ManageBar.start(context) + } data.notifyChange() } override fun onException(e: Exception) { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/TetheringManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/TetheringManager.kt index d99c8229..645e9367 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/TetheringManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/TetheringManager.kt @@ -297,31 +297,38 @@ object TetheringManager { fun startTethering(type: Int, showProvisioningUi: Boolean, callback: StartTetheringCallback, handler: Handler? = null, cacheDir: File = app.deviceStorage.codeCacheDir) { if (Build.VERSION.SDK_INT >= 30) try { - val proxy = proxy(callback) val executor = handler.makeExecutor() - try { - startTethering(type, true, showProvisioningUi, executor, proxy) - } catch (e1: InvocationTargetException) { - if (e1.targetException is SecurityException) GlobalScope.launch(Dispatchers.Unconfined) { - val result = try { - RootManager.use { it.execute(StartTethering(type, showProvisioningUi)) } - } catch (e2: Exception) { - e2.addSuppressed(e1) - try { - // last resort: start tethering without trying to bypass entitlement check - startTethering(type, false, showProvisioningUi, executor, proxy) - Timber.w(e2) - } catch (e3: Exception) { - e3.addSuppressed(e2) - Timber.w(e3) - callback.onException(e3) + startTethering(type, true, showProvisioningUi, + executor, proxy(object : StartTetheringCallback { + override fun onTetheringStarted() = callback.onTetheringStarted() + override fun onTetheringFailed(error: Int?) { + if (error != TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION) callback.onTetheringFailed(error) + else GlobalScope.launch(Dispatchers.Unconfined) { + val result = try { + RootManager.use { it.execute(StartTethering(type, showProvisioningUi)) } + } catch (eRoot: Exception) { + try { // last resort: start tethering without trying to bypass entitlement check + startTethering(type, false, showProvisioningUi, executor, proxy(callback)) + Timber.w(eRoot) + } catch (e: Exception) { + e.addSuppressed(eRoot) + callback.onException(e) + } + return@launch + } + when { + result == null -> callback.onTetheringStarted() + result.value == TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION -> try { + startTethering(type, false, showProvisioningUi, executor, proxy(callback)) + } catch (e: Exception) { + callback.onException(e) + } + else -> callback.onTetheringFailed(result.value) } - return@launch } - if (result == null) callback.onTetheringStarted() - else callback.onTetheringFailed(result.value) - } else callback.onException(e1) - } + } + override fun onException(e: Exception) = callback.onException(e) + })) } catch (e: Exception) { callback.onException(e) } else @Suppress("DEPRECATION") try { @@ -607,6 +614,8 @@ object TetheringManager { "TETHER_ERROR_TETHER_IFACE_ERROR", "TETHER_ERROR_UNTETHER_IFACE_ERROR", "TETHER_ERROR_ENABLE_NAT_ERROR", "TETHER_ERROR_DISABLE_NAT_ERROR", "TETHER_ERROR_IFACE_CFG_ERROR", "TETHER_ERROR_PROVISION_FAILED", "TETHER_ERROR_DHCPSERVER_ERROR", "TETHER_ERROR_ENTITLEMENT_UNKNOWN") { clazz } + @RequiresApi(30) + const val TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14 val Intent.tetheredIfaces get() = getStringArrayListExtra( if (Build.VERSION.SDK_INT >= 26) EXTRA_ACTIVE_TETHER else EXTRA_ACTIVE_TETHER_LEGACY) diff --git a/mobile/src/main/res/values-zh-rCN/strings.xml b/mobile/src/main/res/values-zh-rCN/strings.xml index 51a51ca8..642211d0 100644 --- a/mobile/src/main/res/values-zh-rCN/strings.xml +++ b/mobile/src/main/res/values-zh-rCN/strings.xml @@ -151,6 +151,7 @@ 未知 #%d 错误:未找到下游接口 发生异常,详情请查看调试信息。 + 权限不足 设置 WLAN 使用 QR 码分享 diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml index 0043149f..4e93ef1d 100644 --- a/mobile/src/main/res/values/strings.xml +++ b/mobile/src/main/res/values/strings.xml @@ -1,8 +1,8 @@ @@ -171,6 +171,7 @@ unknown #%d Fatal: Downstream interface not found Something went wrong, please check the debug information. + Permission missing Wi\u2011Fi configuration Share via QR code