Make compatible with F-Droid (#42)
* Make compatible with F-Droid * Fix title bar empty
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply plugin: 'io.fabric'
|
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
|
if (getGradle().getStartParameter().getTaskRequests().toString().contains("base"))
|
||||||
|
apply plugin: 'io.fabric'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
buildToolsVersion "28.0.3"
|
buildToolsVersion "28.0.3"
|
||||||
compileSdkVersion 28
|
compileSdkVersion 28
|
||||||
@@ -31,8 +33,15 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
dataBinding.enabled = true
|
dataBinding.enabled = true
|
||||||
flavorDimensions("freedom")
|
flavorDimensions("fdroid", "freedom")
|
||||||
productFlavors {
|
productFlavors {
|
||||||
|
base {
|
||||||
|
dimension "fdroid"
|
||||||
|
}
|
||||||
|
fdroid {
|
||||||
|
dimension "fdroid"
|
||||||
|
}
|
||||||
|
|
||||||
freedom {
|
freedom {
|
||||||
dimension "freedom"
|
dimension "freedom"
|
||||||
buildConfigField "boolean", "DONATIONS", "true"
|
buildConfigField "boolean", "DONATIONS", "true"
|
||||||
@@ -52,18 +61,20 @@ dependencies {
|
|||||||
implementation "androidx.core:core-ktx:$androidxVersion"
|
implementation "androidx.core:core-ktx:$androidxVersion"
|
||||||
implementation "androidx.preference:preference:$androidxVersion"
|
implementation "androidx.preference:preference:$androidxVersion"
|
||||||
implementation "androidx.room:room-runtime:$roomVersion"
|
implementation "androidx.room:room-runtime:$roomVersion"
|
||||||
implementation 'com.android.billingclient:billing:1.1'
|
|
||||||
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.5'
|
|
||||||
implementation 'com.github.luongvo:BadgeView:1.1.5'
|
implementation 'com.github.luongvo:BadgeView:1.1.5'
|
||||||
implementation 'com.github.topjohnwu:libsu:2.0.2'
|
implementation 'com.github.topjohnwu:libsu:2.0.2'
|
||||||
implementation "com.google.android.material:material:$androidxVersion"
|
implementation "com.google.android.material:material:$androidxVersion"
|
||||||
|
implementation 'com.jakewharton.timber:timber:4.7.1'
|
||||||
implementation 'com.linkedin.dexmaker:dexmaker-mockito:2.19.1'
|
implementation 'com.linkedin.dexmaker:dexmaker-mockito:2.19.1'
|
||||||
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
|
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
|
||||||
|
baseImplementation 'com.android.billingclient:billing:1.1'
|
||||||
|
baseImplementation 'com.crashlytics.sdk.android:crashlytics:2.9.5'
|
||||||
testImplementation "androidx.room:room-testing:$roomVersion"
|
testImplementation "androidx.room:room-testing:$roomVersion"
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
|
androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'com.google.gms.google-services'
|
if (getGradle().getStartParameter().getTaskRequests().toString().contains("base"))
|
||||||
|
apply plugin: 'com.google.gms.google-services'
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package be.mygod.vpnhotspot
|
package be.mygod.vpnhotspot
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@@ -15,7 +14,7 @@ import androidx.core.net.toUri
|
|||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import com.android.billingclient.api.*
|
import com.android.billingclient.api.*
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/java/org/sufficientlysecure/donations/DonationsFragment.java
|
* Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/java/org/sufficientlysecure/donations/DonationsFragment.java
|
||||||
@@ -23,7 +22,6 @@ import com.crashlytics.android.Crashlytics
|
|||||||
class EBegFragment : DialogFragment(), PurchasesUpdatedListener, BillingClientStateListener,
|
class EBegFragment : DialogFragment(), PurchasesUpdatedListener, BillingClientStateListener,
|
||||||
SkuDetailsResponseListener, ConsumeResponseListener {
|
SkuDetailsResponseListener, ConsumeResponseListener {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "EBegFragment"
|
|
||||||
private const val KEY_TITLE = "title"
|
private const val KEY_TITLE = "title"
|
||||||
private const val KEY_MESSAGE = "message"
|
private const val KEY_MESSAGE = "message"
|
||||||
}
|
}
|
||||||
@@ -80,6 +78,7 @@ class EBegFragment : DialogFragment(), PurchasesUpdatedListener, BillingClientSt
|
|||||||
billingClient = BillingClient.newBuilder(context ?: return).setListener(this).build()
|
billingClient = BillingClient.newBuilder(context ?: return).setListener(this).build()
|
||||||
.also { it.startConnection(this) }
|
.also { it.startConnection(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBillingSetupFinished(responseCode: Int) {
|
override fun onBillingSetupFinished(responseCode: Int) {
|
||||||
if (responseCode == BillingClient.BillingResponse.OK) {
|
if (responseCode == BillingClient.BillingResponse.OK) {
|
||||||
billingClient.querySkuDetailsAsync(
|
billingClient.querySkuDetailsAsync(
|
||||||
@@ -88,24 +87,25 @@ class EBegFragment : DialogFragment(), PurchasesUpdatedListener, BillingClientSt
|
|||||||
"donate100", "donate200", "donatemax"))
|
"donate100", "donate200", "donatemax"))
|
||||||
setType(BillingClient.SkuType.INAPP)
|
setType(BillingClient.SkuType.INAPP)
|
||||||
}.build(), this)
|
}.build(), this)
|
||||||
} else Crashlytics.log(Log.ERROR, TAG, "onBillingSetupFinished: $responseCode")
|
} else Timber.e("onBillingSetupFinished: $responseCode")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSkuDetailsResponse(responseCode: Int, skuDetailsList: MutableList<SkuDetails>?) {
|
override fun onSkuDetailsResponse(responseCode: Int, skuDetailsList: MutableList<SkuDetails>?) {
|
||||||
if (responseCode == BillingClient.BillingResponse.OK) skus = skuDetailsList
|
if (responseCode == BillingClient.BillingResponse.OK) skus = skuDetailsList
|
||||||
else Crashlytics.log(Log.ERROR, TAG, "onSkuDetailsResponse: $responseCode")
|
else Timber.e("onSkuDetailsResponse: $responseCode")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPurchasesUpdated(responseCode: Int, purchases: MutableList<Purchase>?) {
|
override fun onPurchasesUpdated(responseCode: Int, purchases: MutableList<Purchase>?) {
|
||||||
if (responseCode == BillingClient.BillingResponse.OK && purchases != null) {
|
if (responseCode == BillingClient.BillingResponse.OK && purchases != null) {
|
||||||
// directly consume in-app purchase, so that people can donate multiple times
|
// directly consume in-app purchase, so that people can donate multiple times
|
||||||
purchases.forEach { billingClient.consumeAsync(it.purchaseToken, this) }
|
purchases.forEach { billingClient.consumeAsync(it.purchaseToken, this) }
|
||||||
} else Crashlytics.log(Log.ERROR, TAG, "onPurchasesUpdated: $responseCode")
|
} else Timber.e("onPurchasesUpdated: $responseCode")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onConsumeResponse(responseCode: Int, purchaseToken: String?) {
|
override fun onConsumeResponse(responseCode: Int, purchaseToken: String?) {
|
||||||
if (responseCode == BillingClient.BillingResponse.OK) {
|
if (responseCode == BillingClient.BillingResponse.OK) {
|
||||||
openDialog(R.string.donations__thanks_dialog_title, R.string.donations__thanks_dialog)
|
openDialog(R.string.donations__thanks_dialog_title, R.string.donations__thanks_dialog)
|
||||||
dismissAllowingStateLoss()
|
dismissAllowingStateLoss()
|
||||||
} else Crashlytics.log(Log.ERROR, TAG, "onConsumeResponse: $responseCode")
|
} else Timber.e("onConsumeResponse: $responseCode")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
25
mobile/src/base/java/be/mygod/vpnhotspot/Timber.kt
Normal file
25
mobile/src/base/java/be/mygod/vpnhotspot/Timber.kt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package be.mygod.vpnhotspot
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
|
import com.crashlytics.android.Crashlytics
|
||||||
|
import io.fabric.sdk.android.Fabric
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
fun initTimber() {
|
||||||
|
Fabric.with(app, Crashlytics())
|
||||||
|
Timber.plant(object : Timber.Tree() {
|
||||||
|
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||||
|
if (t == null) Crashlytics.log(priority, tag, message) else {
|
||||||
|
// Crashlytics.logException doesn't print to logcat
|
||||||
|
if (priority >= Log.WARN || priority == Log.DEBUG) Log.println(priority, tag, message)
|
||||||
|
if (priority >= Log.INFO) Crashlytics.logException(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun debugLog(tag: String?, message: String?) {
|
||||||
|
if (BuildConfig.DEBUG) Timber.d(tag, message)
|
||||||
|
Crashlytics.log("$tag: $message")
|
||||||
|
}
|
||||||
27
mobile/src/fdroid/java/be/mygod/vpnhotspot/EBegFragment.kt
Normal file
27
mobile/src/fdroid/java/be/mygod/vpnhotspot/EBegFragment.kt
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package be.mygod.vpnhotspot
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.ViewStub
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/java/org/sufficientlysecure/donations/DonationsFragment.java
|
||||||
|
*/
|
||||||
|
class EBegFragment : DialogFragment() {
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
|
||||||
|
inflater.inflate(R.layout.fragment_ebeg, container, false)
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
view.findViewById<LinearLayout>(R.id.donations__google).visibility = View.GONE
|
||||||
|
(view.findViewById<ViewStub>(R.id.donations__more_stub).inflate() as Button).setOnClickListener {
|
||||||
|
(activity as MainActivity).launchUrl("https://mygod.be/donate/".toUri())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
mobile/src/fdroid/java/be/mygod/vpnhotspot/Timber.kt
Normal file
7
mobile/src/fdroid/java/be/mygod/vpnhotspot/Timber.kt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package be.mygod.vpnhotspot
|
||||||
|
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
fun initTimber() = Timber.plant(Timber.DebugTree())
|
||||||
|
|
||||||
|
fun debugLog(tag: String?, message: String?) = Timber.d(tag, message)
|
||||||
@@ -45,7 +45,9 @@
|
|||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme"
|
||||||
|
tools:ignore="GoogleAppIndexingWarning">
|
||||||
|
|
||||||
<meta-data android:name="firebase_crashlytics_collection_enabled"
|
<meta-data android:name="firebase_crashlytics_collection_enabled"
|
||||||
android:value="false"/>
|
android:value="false"/>
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ import be.mygod.vpnhotspot.room.AppDatabase
|
|||||||
import be.mygod.vpnhotspot.util.DeviceStorageApp
|
import be.mygod.vpnhotspot.util.DeviceStorageApp
|
||||||
import be.mygod.vpnhotspot.util.Event0
|
import be.mygod.vpnhotspot.util.Event0
|
||||||
import be.mygod.vpnhotspot.util.RootSession
|
import be.mygod.vpnhotspot.util.RootSession
|
||||||
import com.crashlytics.android.Crashlytics
|
|
||||||
import io.fabric.sdk.android.Fabric
|
|
||||||
|
|
||||||
class App : Application() {
|
class App : Application() {
|
||||||
companion object {
|
companion object {
|
||||||
@@ -33,7 +31,7 @@ class App : Application() {
|
|||||||
deviceStorage.moveSharedPreferencesFrom(this, PreferenceManager.getDefaultSharedPreferencesName(this))
|
deviceStorage.moveSharedPreferencesFrom(this, PreferenceManager.getDefaultSharedPreferencesName(this))
|
||||||
deviceStorage.moveDatabaseFrom(this, AppDatabase.DB_NAME)
|
deviceStorage.moveDatabaseFrom(this, AppDatabase.DB_NAME)
|
||||||
} else deviceStorage = this
|
} else deviceStorage = this
|
||||||
Fabric.with(deviceStorage, Crashlytics())
|
initTimber()
|
||||||
ServiceNotification.updateNotificationChannels()
|
ServiceNotification.updateNotificationChannels()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,8 @@ import be.mygod.vpnhotspot.manage.LocalOnlyHotspotManager
|
|||||||
import be.mygod.vpnhotspot.net.IpNeighbourMonitor
|
import be.mygod.vpnhotspot.net.IpNeighbourMonitor
|
||||||
import be.mygod.vpnhotspot.net.TetheringManager
|
import be.mygod.vpnhotspot.net.TetheringManager
|
||||||
import be.mygod.vpnhotspot.util.broadcastReceiver
|
import be.mygod.vpnhotspot.util.broadcastReceiver
|
||||||
import be.mygod.vpnhotspot.util.debugLog
|
|
||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(26)
|
||||||
class LocalOnlyHotspotService : IpNeighbourMonitoringService() {
|
class LocalOnlyHotspotService : IpNeighbourMonitoringService() {
|
||||||
@@ -90,23 +89,23 @@ class LocalOnlyHotspotService : IpNeighbourMonitoringService() {
|
|||||||
else -> getString(R.string.failure_reason_unknown, reason)
|
else -> getString(R.string.failure_reason_unknown, reason)
|
||||||
})
|
})
|
||||||
SmartSnackbar.make(message).show()
|
SmartSnackbar.make(message).show()
|
||||||
startFailure(if (reason == WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE) null else
|
if (reason != WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE) {
|
||||||
StartFailure(message))
|
Timber.i(StartFailure(message))
|
||||||
|
}
|
||||||
|
startFailure()
|
||||||
}
|
}
|
||||||
}, app.handler)
|
}, app.handler)
|
||||||
} catch (e: IllegalStateException) {
|
// assuming IllegalStateException will be thrown only if
|
||||||
e.printStackTrace()
|
// "Caller already has an active LocalOnlyHotspot request"
|
||||||
startFailure(e)
|
} catch (_: IllegalStateException) { } catch (e: SecurityException) {
|
||||||
} catch (e: SecurityException) {
|
|
||||||
SmartSnackbar.make(e.localizedMessage).show()
|
SmartSnackbar.make(e.localizedMessage).show()
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
startFailure(e)
|
startFailure()
|
||||||
}
|
}
|
||||||
return START_STICKY
|
return START_STICKY
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startFailure(e: Exception?) {
|
private fun startFailure() {
|
||||||
if (e?.message != "Caller already has an active LocalOnlyHotspot request") Crashlytics.logException(e)
|
|
||||||
updateNotification()
|
updateNotification()
|
||||||
ServiceNotification.stopForeground(this@LocalOnlyHotspotService)
|
ServiceNotification.stopForeground(this@LocalOnlyHotspotService)
|
||||||
stopSelf()
|
stopSelf()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import be.mygod.vpnhotspot.App.Companion.app
|
|||||||
import be.mygod.vpnhotspot.net.Routing
|
import be.mygod.vpnhotspot.net.Routing
|
||||||
import be.mygod.vpnhotspot.net.UpstreamMonitor
|
import be.mygod.vpnhotspot.net.UpstreamMonitor
|
||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.net.InterfaceAddress
|
import java.net.InterfaceAddress
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ class LocalOnlyInterfaceManager(private val owner: Context, val downstream: Stri
|
|||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
SmartSnackbar.make(e.localizedMessage).show()
|
SmartSnackbar.make(e.localizedMessage).show()
|
||||||
Crashlytics.logException(e)
|
Timber.w(e)
|
||||||
routing = null
|
routing = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ import be.mygod.vpnhotspot.databinding.ActivityMainBinding
|
|||||||
import be.mygod.vpnhotspot.manage.TetheringFragment
|
import be.mygod.vpnhotspot.manage.TetheringFragment
|
||||||
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
|
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
|
||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
import com.crashlytics.android.Crashlytics
|
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationMenuView
|
import com.google.android.material.bottomnavigation.BottomNavigationMenuView
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
import q.rorbin.badgeview.QBadgeView
|
import q.rorbin.badgeview.QBadgeView
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemSelectedListener, ServiceConnection {
|
class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemSelectedListener, ServiceConnection {
|
||||||
companion object {
|
companion object {
|
||||||
@@ -38,15 +38,14 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
|
|||||||
.setToolbarColor(ContextCompat.getColor(this, R.color.colorPrimary))
|
.setToolbarColor(ContextCompat.getColor(this, R.color.colorPrimary))
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun launchUrl(url: Uri) = try {
|
fun launchUrl(url: Uri) = try {
|
||||||
customTabsIntent.launchUrl(this, url)
|
customTabsIntent.launchUrl(this, url)
|
||||||
} catch (e: ActivityNotFoundException) {
|
} catch (e: ActivityNotFoundException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
SmartSnackbar.make(url.toString()).show()
|
SmartSnackbar.make(url.toString()).show()
|
||||||
} catch (e: SecurityException) {
|
} catch (e: SecurityException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
SmartSnackbar.make(url.toString()).show()
|
SmartSnackbar.make(url.toString()).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.setWifiP2pChannels
|
|||||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.startWps
|
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.startWps
|
||||||
import be.mygod.vpnhotspot.util.*
|
import be.mygod.vpnhotspot.util.*
|
||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
import java.lang.reflect.InvocationTargetException
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
|
||||||
class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
@@ -33,7 +33,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
|||||||
enum class Status {
|
enum class Status {
|
||||||
IDLE, STARTING, ACTIVE
|
IDLE, STARTING, ACTIVE
|
||||||
}
|
}
|
||||||
private class Failure(message: String) : RuntimeException(message)
|
private class Failure(message: String, cause: Throwable? = null) : RuntimeException(message, cause)
|
||||||
|
|
||||||
inner class Binder : android.os.Binder() {
|
inner class Binder : android.os.Binder() {
|
||||||
val service get() = this@RepeaterService
|
val service get() = this@RepeaterService
|
||||||
@@ -79,8 +79,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
|||||||
if (it.size == 1) group = it.single()
|
if (it.size == 1) group = it.single()
|
||||||
}
|
}
|
||||||
} catch (e: ReflectiveOperationException) {
|
} catch (e: ReflectiveOperationException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
SmartSnackbar.make(e.localizedMessage).show()
|
SmartSnackbar.make(e.localizedMessage).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,7 +123,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
|||||||
WifiP2pManagerHelper.UNSUPPORTED -> getString(R.string.repeater_failure_reason_unsupported_operation)
|
WifiP2pManagerHelper.UNSUPPORTED -> getString(R.string.repeater_failure_reason_unsupported_operation)
|
||||||
else -> getString(R.string.failure_reason_unknown, reason)
|
else -> getString(R.string.failure_reason_unknown, reason)
|
||||||
})
|
})
|
||||||
Crashlytics.logException(Failure(result))
|
Timber.i(Failure(result))
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,9 +133,8 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
|||||||
p2pManager = getSystemService()!!
|
p2pManager = getSystemService()!!
|
||||||
onChannelDisconnected()
|
onChannelDisconnected()
|
||||||
app.pref.registerOnSharedPreferenceChangeListener(this)
|
app.pref.registerOnSharedPreferenceChangeListener(this)
|
||||||
} catch (exc: RuntimeException) {
|
} catch (e: RuntimeException) {
|
||||||
exc.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(exc)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,10 +152,8 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
|||||||
if (oc != 0) {
|
if (oc != 0) {
|
||||||
val message = getString(R.string.repeater_set_oc_failure, e.message)
|
val message = getString(R.string.repeater_set_oc_failure, e.message)
|
||||||
SmartSnackbar.make(message).show()
|
SmartSnackbar.make(message).show()
|
||||||
Crashlytics.logException(Failure(message))
|
Timber.w(Failure(message, e))
|
||||||
}
|
} else Timber.w(e)
|
||||||
e.printStackTrace()
|
|
||||||
Crashlytics.logException(e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onChannelDisconnected() {
|
override fun onChannelDisconnected() {
|
||||||
@@ -179,8 +175,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
|||||||
val out = try {
|
val out = try {
|
||||||
RootSession.use { it.execOut("dumpsys ${Context.WIFI_P2P_SERVICE}") }
|
RootSession.use { it.execOut("dumpsys ${Context.WIFI_P2P_SERVICE}") }
|
||||||
} catch (e: RuntimeException) {
|
} catch (e: RuntimeException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
startFailure(e.localizedMessage)
|
startFailure(e.localizedMessage)
|
||||||
return START_NOT_STICKY
|
return START_NOT_STICKY
|
||||||
}
|
}
|
||||||
@@ -197,7 +192,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
|||||||
it == null -> doStart()
|
it == null -> doStart()
|
||||||
it.isGroupOwner -> if (routingManager == null) doStart(it)
|
it.isGroupOwner -> if (routingManager == null) doStart(it)
|
||||||
else -> {
|
else -> {
|
||||||
Crashlytics.log(Log.INFO, TAG, "Removing old group ($it)")
|
Timber.i("Removing old group ($it)")
|
||||||
p2pManager.removeGroup(channel, object : WifiP2pManager.ActionListener {
|
p2pManager.removeGroup(channel, object : WifiP2pManager.ActionListener {
|
||||||
override fun onSuccess() = doStart()
|
override fun onSuccess() = doStart()
|
||||||
override fun onFailure(reason: Int) {
|
override fun onFailure(reason: Int) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.os.Bundle
|
|||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.SwitchPreference
|
import androidx.preference.SwitchPreference
|
||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
@@ -16,8 +17,8 @@ import be.mygod.vpnhotspot.preference.AlwaysAutoCompleteEditTextPreferenceDialog
|
|||||||
import be.mygod.vpnhotspot.preference.SharedPreferenceDataStore
|
import be.mygod.vpnhotspot.preference.SharedPreferenceDataStore
|
||||||
import be.mygod.vpnhotspot.util.RootSession
|
import be.mygod.vpnhotspot.util.RootSession
|
||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
import com.crashlytics.android.Crashlytics
|
|
||||||
import com.takisoft.preferencex.PreferenceFragmentCompat
|
import com.takisoft.preferencex.PreferenceFragmentCompat
|
||||||
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
@@ -39,7 +40,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
|||||||
Routing.clean()
|
Routing.clean()
|
||||||
true
|
true
|
||||||
} catch (e: RuntimeException) {
|
} catch (e: RuntimeException) {
|
||||||
e.printStackTrace()
|
Timber.d(e)
|
||||||
SmartSnackbar.make(e.localizedMessage).show()
|
SmartSnackbar.make(e.localizedMessage).show()
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@@ -58,8 +59,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
|||||||
try {
|
try {
|
||||||
Runtime.getRuntime().exec(arrayOf("logcat", "-d")).inputStream.use { it.copyTo(out) }
|
Runtime.getRuntime().exec(arrayOf("logcat", "-d")).inputStream.use { it.copyTo(out) }
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace(writer)
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
}
|
}
|
||||||
writer.write("\n")
|
writer.write("\n")
|
||||||
writer.flush()
|
writer.flush()
|
||||||
@@ -93,8 +93,8 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
|||||||
.joinToString("\n").toByteArray())
|
.joinToString("\n").toByteArray())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace(writer)
|
e.printStackTrace(writer)
|
||||||
Crashlytics.logException(e)
|
|
||||||
writer.flush()
|
writer.flush()
|
||||||
|
Timber.i(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
findPreference("misc.donate").setOnPreferenceClickListener {
|
findPreference("misc.donate").setOnPreferenceClickListener {
|
||||||
EBegFragment().show(fragmentManager, "ebeg_fragment")
|
EBegFragment().apply { setStyle(DialogFragment.STYLE_NO_TITLE, 0) }.show(fragmentManager, "EBegFragment")
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,8 +125,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
|||||||
.filter { it.isUp && !it.isLoopback && it.interfaceAddresses.isNotEmpty() }
|
.filter { it.isUp && !it.isLoopback && it.interfaceAddresses.isNotEmpty() }
|
||||||
.map { it.name }.sorted().toList().toTypedArray()
|
.map { it.name }.sorted().toList().toTypedArray()
|
||||||
} catch (e: SocketException) {
|
} catch (e: SocketException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
emptyArray<String>()
|
emptyArray<String>()
|
||||||
})))
|
})))
|
||||||
else -> super.onDisplayPreferenceDialog(preference)
|
else -> super.onDisplayPreferenceDialog(preference)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import be.mygod.vpnhotspot.net.TetheringManager
|
|||||||
import be.mygod.vpnhotspot.net.UpstreamMonitor
|
import be.mygod.vpnhotspot.net.UpstreamMonitor
|
||||||
import be.mygod.vpnhotspot.util.broadcastReceiver
|
import be.mygod.vpnhotspot.util.broadcastReceiver
|
||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
|
|
||||||
class TetheringService : IpNeighbourMonitoringService(), UpstreamMonitor.Callback {
|
class TetheringService : IpNeighbourMonitoringService(), UpstreamMonitor.Callback {
|
||||||
@@ -84,8 +84,7 @@ class TetheringService : IpNeighbourMonitoringService(), UpstreamMonitor.Callbac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
SmartSnackbar.make(e.localizedMessage).show()
|
SmartSnackbar.make(e.localizedMessage).show()
|
||||||
iterator.remove()
|
iterator.remove()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding
|
|||||||
import be.mygod.vpnhotspot.net.TetherType
|
import be.mygod.vpnhotspot.net.TetherType
|
||||||
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
|
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
|
||||||
import be.mygod.vpnhotspot.util.formatAddresses
|
import be.mygod.vpnhotspot.util.formatAddresses
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
import java.net.NetworkInterface
|
import java.net.NetworkInterface
|
||||||
|
|
||||||
@TargetApi(26)
|
@TargetApi(26)
|
||||||
@@ -60,9 +60,8 @@ class LocalOnlyHotspotManager(private val parent: TetheringFragment) : Manager()
|
|||||||
Toast.makeText(view.context, R.string.tethering_temp_hotspot_location, Toast.LENGTH_LONG).show()
|
Toast.makeText(view.context, R.string.tethering_temp_hotspot_location, Toast.LENGTH_LONG).show()
|
||||||
try {
|
try {
|
||||||
view.context.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
|
view.context.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
|
||||||
} catch (exc: ActivityNotFoundException) {
|
} catch (e: ActivityNotFoundException) {
|
||||||
exc.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(exc)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import androidx.databinding.BaseObservable
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
import be.mygod.vpnhotspot.databinding.ListitemManageBinding
|
import be.mygod.vpnhotspot.databinding.ListitemManageBinding
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
|
|
||||||
object ManageBar : Manager() {
|
object ManageBar : Manager() {
|
||||||
object Data : BaseObservable() {
|
object Data : BaseObservable() {
|
||||||
@@ -51,14 +51,11 @@ object ManageBar : Manager() {
|
|||||||
try {
|
try {
|
||||||
context.startActivity(Intent()
|
context.startActivity(Intent()
|
||||||
.setClassName("com.android.settings", "com.android.settings.TetherSettings"))
|
.setClassName("com.android.settings", "com.android.settings.TetherSettings"))
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
} catch (e: ActivityNotFoundException) {
|
} catch (e: ActivityNotFoundException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
} catch (e: SecurityException) {
|
} catch (e: SecurityException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import be.mygod.vpnhotspot.net.wifi.WifiP2pDialogFragment
|
|||||||
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
|
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
|
||||||
import be.mygod.vpnhotspot.util.formatAddresses
|
import be.mygod.vpnhotspot.util.formatAddresses
|
||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
import java.net.NetworkInterface
|
import java.net.NetworkInterface
|
||||||
import java.net.SocketException
|
import java.net.SocketException
|
||||||
|
|
||||||
@@ -47,8 +47,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
|||||||
return try {
|
return try {
|
||||||
NetworkInterface.getByName(p2pInterface ?: return "")?.formatAddresses() ?: ""
|
NetworkInterface.getByName(p2pInterface ?: return "")?.formatAddresses() ?: ""
|
||||||
} catch (e: SocketException) {
|
} catch (e: SocketException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,8 +173,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
|||||||
.update(data.getParcelableExtra(WifiP2pDialogFragment.KEY_CONFIGURATION))
|
.update(data.getParcelableExtra(WifiP2pDialogFragment.KEY_CONFIGURATION))
|
||||||
app.handler.postDelayed(binder!!::requestGroupUpdate, 1000)
|
app.handler.postDelayed(binder!!::requestGroupUpdate, 1000)
|
||||||
} catch (e: RuntimeException) {
|
} catch (e: RuntimeException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
SmartSnackbar.make(e.localizedMessage).show()
|
SmartSnackbar.make(e.localizedMessage).show()
|
||||||
}
|
}
|
||||||
DialogInterface.BUTTON_NEUTRAL -> binder!!.resetCredentials()
|
DialogInterface.BUTTON_NEUTRAL -> binder!!.resetCredentials()
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import be.mygod.vpnhotspot.net.TetherType
|
|||||||
import be.mygod.vpnhotspot.net.TetheringManager
|
import be.mygod.vpnhotspot.net.TetheringManager
|
||||||
import be.mygod.vpnhotspot.net.wifi.WifiApManager
|
import be.mygod.vpnhotspot.net.wifi.WifiApManager
|
||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.lang.reflect.InvocationTargetException
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
|
||||||
@@ -51,21 +51,18 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
|
|||||||
manager.parent.startActivity(Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS,
|
manager.parent.startActivity(Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS,
|
||||||
"package:${mainActivity.packageName}".toUri()))
|
"package:${mainActivity.packageName}".toUri()))
|
||||||
return
|
return
|
||||||
} catch (exc: ActivityNotFoundException) {
|
} catch (e: ActivityNotFoundException) {
|
||||||
exc.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(exc)
|
|
||||||
}
|
}
|
||||||
val started = manager.isStarted
|
val started = manager.isStarted
|
||||||
try {
|
try {
|
||||||
if (started) manager.stop() else manager.start()
|
if (started) manager.stop() else manager.start()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
Toast.makeText(mainActivity, e.localizedMessage, Toast.LENGTH_LONG).show()
|
Toast.makeText(mainActivity, e.localizedMessage, Toast.LENGTH_LONG).show()
|
||||||
ManageBar.start(itemView.context)
|
ManageBar.start(itemView.context)
|
||||||
} catch (e: InvocationTargetException) {
|
} catch (e: InvocationTargetException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
var cause: Throwable? = e
|
var cause: Throwable? = e
|
||||||
while (cause != null) {
|
while (cause != null) {
|
||||||
cause = cause.cause
|
cause = cause.cause
|
||||||
@@ -125,7 +122,7 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
|
|||||||
else -> app.getString(R.string.failure_reason_unknown, error)
|
else -> app.getString(R.string.failure_reason_unknown, error)
|
||||||
}
|
}
|
||||||
} catch (e: InvocationTargetException) {
|
} catch (e: InvocationTargetException) {
|
||||||
Crashlytics.logException(e)
|
Timber.w(e)
|
||||||
e.localizedMessage
|
e.localizedMessage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,8 +168,7 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
|
|||||||
try {
|
try {
|
||||||
BluetoothAdapter.getDefaultAdapter()?.getProfileProxy(parent.requireContext(), this, PAN)
|
BluetoothAdapter.getDefaultAdapter()?.getProfileProxy(parent.requireContext(), this, PAN)
|
||||||
} catch (e: SecurityException) {
|
} catch (e: SecurityException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
SmartSnackbar.make(e.localizedMessage).show()
|
SmartSnackbar.make(e.localizedMessage).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import be.mygod.vpnhotspot.net.TetherType
|
|||||||
import be.mygod.vpnhotspot.net.TetheringManager
|
import be.mygod.vpnhotspot.net.TetheringManager
|
||||||
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
|
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
|
||||||
import be.mygod.vpnhotspot.util.broadcastReceiver
|
import be.mygod.vpnhotspot.util.broadcastReceiver
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
import java.net.NetworkInterface
|
import java.net.NetworkInterface
|
||||||
import java.net.SocketException
|
import java.net.SocketException
|
||||||
|
|
||||||
@@ -53,8 +53,7 @@ class TetheringFragment : Fragment(), ServiceConnection {
|
|||||||
ifaceLookup = try {
|
ifaceLookup = try {
|
||||||
NetworkInterface.getNetworkInterfaces().asSequence().associateBy { it.name }
|
NetworkInterface.getNetworkInterfaces().asSequence().associateBy { it.name }
|
||||||
} catch (e: SocketException) {
|
} catch (e: SocketException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
emptyMap()
|
emptyMap()
|
||||||
}
|
}
|
||||||
this@TetheringFragment.enabledTypes =
|
this@TetheringFragment.enabledTypes =
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import android.util.Log
|
|||||||
import be.mygod.vpnhotspot.R
|
import be.mygod.vpnhotspot.R
|
||||||
import be.mygod.vpnhotspot.util.thread
|
import be.mygod.vpnhotspot.util.thread
|
||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InterruptedIOException
|
import java.io.InterruptedIOException
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
@@ -25,25 +25,21 @@ abstract class IpMonitor : Runnable {
|
|||||||
val process = try {
|
val process = try {
|
||||||
builder.start()
|
builder.start()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
Timber.d(e)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
monitor = process
|
monitor = process
|
||||||
val err = thread("${javaClass.simpleName}-error") {
|
val err = thread("${javaClass.simpleName}-error") {
|
||||||
try {
|
try {
|
||||||
process.errorStream.bufferedReader().forEachLine {
|
process.errorStream.bufferedReader().forEachLine { Timber.e(it) }
|
||||||
Crashlytics.log(Log.ERROR, javaClass.simpleName, it)
|
|
||||||
}
|
|
||||||
} catch (_: InterruptedIOException) { } catch (e: IOException) {
|
} catch (_: InterruptedIOException) { } catch (e: IOException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
process.inputStream.bufferedReader().forEachLine(this::processLine)
|
process.inputStream.bufferedReader().forEachLine(this::processLine)
|
||||||
} catch (_: InterruptedIOException) { } catch (e: IOException) {
|
} catch (_: InterruptedIOException) { } catch (e: IOException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
}
|
}
|
||||||
err.join()
|
err.join()
|
||||||
process.waitFor()
|
process.waitFor()
|
||||||
@@ -56,8 +52,8 @@ abstract class IpMonitor : Runnable {
|
|||||||
// monitor may get rejected by SELinux
|
// monitor may get rejected by SELinux
|
||||||
if (handleProcess(ProcessBuilder("ip", "monitor", monitoredObject))) return@thread
|
if (handleProcess(ProcessBuilder("ip", "monitor", monitoredObject))) return@thread
|
||||||
if (handleProcess(ProcessBuilder("su", "-c", "exec ip monitor $monitoredObject"))) return@thread
|
if (handleProcess(ProcessBuilder("su", "-c", "exec ip monitor $monitoredObject"))) return@thread
|
||||||
Crashlytics.log(Log.WARN, javaClass.simpleName, "Failed to set up monitor, switching to polling")
|
Timber.w("Failed to set up monitor, switching to polling")
|
||||||
Crashlytics.logException(MonitorFailure())
|
Timber.i(MonitorFailure())
|
||||||
val pool = Executors.newScheduledThreadPool(1)
|
val pool = Executors.newScheduledThreadPool(1)
|
||||||
pool.scheduleAtFixedRate(this, 1, 1, TimeUnit.SECONDS)
|
pool.scheduleAtFixedRate(this, 1, 1, TimeUnit.SECONDS)
|
||||||
this.pool = pool
|
this.pool = pool
|
||||||
@@ -74,8 +70,8 @@ abstract class IpMonitor : Runnable {
|
|||||||
thread("${javaClass.simpleName}-flush-error") {
|
thread("${javaClass.simpleName}-flush-error") {
|
||||||
val err = process.errorStream.bufferedReader().readText()
|
val err = process.errorStream.bufferedReader().readText()
|
||||||
if (err.isNotBlank()) {
|
if (err.isNotBlank()) {
|
||||||
Crashlytics.log(Log.ERROR, javaClass.simpleName, err)
|
Timber.e(err)
|
||||||
Crashlytics.logException(FlushFailure())
|
Timber.i(FlushFailure())
|
||||||
SmartSnackbar.make(R.string.noisy_su_failure).show()
|
SmartSnackbar.make(R.string.noisy_su_failure).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
package be.mygod.vpnhotspot.net
|
package be.mygod.vpnhotspot.net
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import be.mygod.vpnhotspot.util.parseNumericAddressNoThrow
|
import be.mygod.vpnhotspot.util.parseNumericAddressNoThrow
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
@@ -13,8 +12,6 @@ data class IpNeighbour(val ip: InetAddress, val dev: String, val lladdr: String,
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "IpNeighbour"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parser based on:
|
* Parser based on:
|
||||||
* https://android.googlesource.com/platform/external/iproute2/+/ad0a6a2/ip/ipneigh.c#194
|
* https://android.googlesource.com/platform/external/iproute2/+/ad0a6a2/ip/ipneigh.c#194
|
||||||
@@ -28,7 +25,7 @@ data class IpNeighbour(val ip: InetAddress, val dev: String, val lladdr: String,
|
|||||||
fun parse(line: String): IpNeighbour? {
|
fun parse(line: String): IpNeighbour? {
|
||||||
val match = parser.matchEntire(line)
|
val match = parser.matchEntire(line)
|
||||||
if (match == null) {
|
if (match == null) {
|
||||||
if (line.isNotEmpty()) Crashlytics.log(Log.WARN, TAG, line)
|
if (line.isNotEmpty()) Timber.w(line)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val ip = parseNumericAddressNoThrow(match.groupValues[2]) ?: return null
|
val ip = parseNumericAddressNoThrow(match.groupValues[2]) ?: return null
|
||||||
@@ -47,7 +44,7 @@ data class IpNeighbour(val ip: InetAddress, val dev: String, val lladdr: String,
|
|||||||
"FAILED" -> State.FAILED
|
"FAILED" -> State.FAILED
|
||||||
"NOARP" -> return null // skip
|
"NOARP" -> return null // skip
|
||||||
else -> {
|
else -> {
|
||||||
Crashlytics.log(Log.WARN, TAG, "Unknown state encountered: ${match.groupValues[10]}")
|
Timber.w("Unknown state encountered: ${match.groupValues[10]}")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,8 +70,7 @@ data class IpNeighbour(val ip: InetAddress, val dev: String, val lladdr: String,
|
|||||||
.filter { it.size >= 6 && mac.matcher(it[ARP_HW_ADDRESS]).matches() }
|
.filter { it.size >= 6 && mac.matcher(it[ARP_HW_ADDRESS]).matches() }
|
||||||
.toList()
|
.toList()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
}
|
}
|
||||||
return arpCache
|
return arpCache
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package be.mygod.vpnhotspot.net
|
package be.mygod.vpnhotspot.net
|
||||||
|
|
||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
import be.mygod.vpnhotspot.util.debugLog
|
import be.mygod.vpnhotspot.debugLog
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
|
|
||||||
class IpNeighbourMonitor private constructor() : IpMonitor() {
|
class IpNeighbourMonitor private constructor() : IpMonitor() {
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ import be.mygod.vpnhotspot.App.Companion.app
|
|||||||
import be.mygod.vpnhotspot.R
|
import be.mygod.vpnhotspot.R
|
||||||
import be.mygod.vpnhotspot.client.Client
|
import be.mygod.vpnhotspot.client.Client
|
||||||
import be.mygod.vpnhotspot.client.ClientMonitorService
|
import be.mygod.vpnhotspot.client.ClientMonitorService
|
||||||
|
import be.mygod.vpnhotspot.debugLog
|
||||||
import be.mygod.vpnhotspot.util.RootSession
|
import be.mygod.vpnhotspot.util.RootSession
|
||||||
import be.mygod.vpnhotspot.util.computeIfAbsentCompat
|
import be.mygod.vpnhotspot.util.computeIfAbsentCompat
|
||||||
import be.mygod.vpnhotspot.util.debugLog
|
|
||||||
import be.mygod.vpnhotspot.util.stopAndUnbind
|
import be.mygod.vpnhotspot.util.stopAndUnbind
|
||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
import java.net.*
|
import java.net.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -165,8 +165,7 @@ class Routing(private val owner: Context, val upstream: String?, private val dow
|
|||||||
try {
|
try {
|
||||||
subroutes.computeIfAbsentCompat(ip) { Subroute(ip, client) }
|
subroutes.computeIfAbsentCompat(ip) { Subroute(ip, client) }
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Crashlytics.logException(e)
|
Timber.w(e)
|
||||||
e.printStackTrace()
|
|
||||||
SmartSnackbar.make(e.localizedMessage).show()
|
SmartSnackbar.make(e.localizedMessage).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,10 @@ import android.net.ConnectivityManager
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.util.Log
|
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
import com.android.dx.stock.ProxyBuilder
|
import com.android.dx.stock.ProxyBuilder
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Heavily based on:
|
* Heavily based on:
|
||||||
@@ -32,8 +31,6 @@ object TetheringManager {
|
|||||||
fun onTetheringFailed() { }
|
fun onTetheringFailed() { }
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val TAG = "TetheringManager"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a sticky broadcast since almost forever.
|
* This is a sticky broadcast since almost forever.
|
||||||
*
|
*
|
||||||
@@ -121,7 +118,7 @@ object TetheringManager {
|
|||||||
val proxy = ProxyBuilder.forClass(classOnStartTetheringCallback)
|
val proxy = ProxyBuilder.forClass(classOnStartTetheringCallback)
|
||||||
.dexCache(app.cacheDir)
|
.dexCache(app.cacheDir)
|
||||||
.handler { proxy, method, args ->
|
.handler { proxy, method, args ->
|
||||||
if (args.isNotEmpty()) Crashlytics.log(Log.WARN, TAG, "Unexpected args for ${method.name}: $args")
|
if (args.isNotEmpty()) Timber.w("Unexpected args for ${method.name}: $args")
|
||||||
when (method.name) {
|
when (method.name) {
|
||||||
"onTetheringStarted" -> {
|
"onTetheringStarted" -> {
|
||||||
callback.onTetheringStarted()
|
callback.onTetheringStarted()
|
||||||
@@ -132,7 +129,7 @@ object TetheringManager {
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
Crashlytics.log(Log.WARN, TAG, "Unexpected method, calling super: $method")
|
Timber.w("Unexpected method, calling super: $method")
|
||||||
ProxyBuilder.callSuper(proxy, method, args)
|
ProxyBuilder.callSuper(proxy, method, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package be.mygod.vpnhotspot.net
|
package be.mygod.vpnhotspot.net
|
||||||
|
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
import android.util.Log
|
|
||||||
import android.util.LongSparseArray
|
import android.util.LongSparseArray
|
||||||
import be.mygod.vpnhotspot.room.AppDatabase
|
import be.mygod.vpnhotspot.room.AppDatabase
|
||||||
import be.mygod.vpnhotspot.room.TrafficRecord
|
import be.mygod.vpnhotspot.room.TrafficRecord
|
||||||
@@ -10,7 +9,7 @@ import be.mygod.vpnhotspot.room.macToLong
|
|||||||
import be.mygod.vpnhotspot.util.Event2
|
import be.mygod.vpnhotspot.util.Event2
|
||||||
import be.mygod.vpnhotspot.util.RootSession
|
import be.mygod.vpnhotspot.util.RootSession
|
||||||
import be.mygod.vpnhotspot.util.parseNumericAddress
|
import be.mygod.vpnhotspot.util.parseNumericAddress
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
@@ -112,9 +111,8 @@ object TrafficRecorder {
|
|||||||
else -> check(false)
|
else -> check(false)
|
||||||
}
|
}
|
||||||
} catch (e: RuntimeException) {
|
} catch (e: RuntimeException) {
|
||||||
Crashlytics.log(Log.WARN, TAG, line)
|
Timber.w(line)
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ((_, record) in records) if (record.id == null) {
|
for ((_, record) in records) if (record.id == null) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import android.net.Network
|
|||||||
import android.net.NetworkCapabilities
|
import android.net.NetworkCapabilities
|
||||||
import android.net.NetworkRequest
|
import android.net.NetworkRequest
|
||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
import be.mygod.vpnhotspot.util.debugLog
|
import be.mygod.vpnhotspot.debugLog
|
||||||
|
|
||||||
object VpnMonitor : UpstreamMonitor() {
|
object VpnMonitor : UpstreamMonitor() {
|
||||||
private const val TAG = "VpnMonitor"
|
private const val TAG = "VpnMonitor"
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ import android.net.wifi.WifiConfiguration
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.util.Log
|
|
||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
import be.mygod.vpnhotspot.util.RootSession
|
import be.mygod.vpnhotspot.util.RootSession
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
@@ -16,7 +15,6 @@ class P2pSupplicantConfiguration(private val initContent: String? = null) : Parc
|
|||||||
override fun createFromParcel(parcel: Parcel) = P2pSupplicantConfiguration(parcel.readString())
|
override fun createFromParcel(parcel: Parcel) = P2pSupplicantConfiguration(parcel.readString())
|
||||||
override fun newArray(size: Int): Array<P2pSupplicantConfiguration?> = arrayOfNulls(size)
|
override fun newArray(size: Int): Array<P2pSupplicantConfiguration?> = 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
|
* Format for ssid is much more complicated, therefore we are only trying to find the line and rely on
|
||||||
* Android's results instead.
|
* Android's results instead.
|
||||||
@@ -55,9 +53,8 @@ class P2pSupplicantConfiguration(private val initContent: String? = null) : Parc
|
|||||||
} catch (e: NoSuchElementException) {
|
} catch (e: NoSuchElementException) {
|
||||||
null
|
null
|
||||||
} catch (e: RuntimeException) {
|
} catch (e: RuntimeException) {
|
||||||
if (contentDelegate.isInitialized()) Crashlytics.log(Log.WARN, TAG, content)
|
if (contentDelegate.isInitialized()) Timber.w(content)
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,9 +79,9 @@ class P2pSupplicantConfiguration(private val initContent: String? = null) : Parc
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (ssidFound != 1 || pskFound != 1) {
|
if (ssidFound != 1 || pskFound != 1) {
|
||||||
Crashlytics.log(Log.WARN, TAG, "Invalid conf ($ssidFound, $pskFound): $content")
|
Timber.w("Invalid conf ($ssidFound, $pskFound): $content")
|
||||||
if (ssidFound == 0 || pskFound == 0) throw InvalidConfigurationError()
|
if (ssidFound == 0 || pskFound == 0) throw InvalidConfigurationError()
|
||||||
else Crashlytics.logException(InvalidConfigurationError())
|
else Timber.i(InvalidConfigurationError())
|
||||||
}
|
}
|
||||||
// pkill not available on Lollipop. Source: https://android.googlesource.com/platform/system/core/+/master/shell_and_utilities/README.md
|
// pkill not available on Lollipop. Source: https://android.googlesource.com/platform/system/core/+/master/shell_and_utilities/README.md
|
||||||
RootSession.use {
|
RootSession.use {
|
||||||
|
|||||||
@@ -4,14 +4,12 @@ import android.annotation.SuppressLint
|
|||||||
import android.net.wifi.WpsInfo
|
import android.net.wifi.WpsInfo
|
||||||
import android.net.wifi.p2p.WifiP2pGroup
|
import android.net.wifi.p2p.WifiP2pGroup
|
||||||
import android.net.wifi.p2p.WifiP2pManager
|
import android.net.wifi.p2p.WifiP2pManager
|
||||||
import android.util.Log
|
|
||||||
import com.android.dx.stock.ProxyBuilder
|
import com.android.dx.stock.ProxyBuilder
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
import java.lang.reflect.Proxy
|
import java.lang.reflect.Proxy
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
object WifiP2pManagerHelper {
|
object WifiP2pManagerHelper {
|
||||||
private const val TAG = "WifiP2pManagerHelper"
|
|
||||||
const val UNSUPPORTED = -2
|
const val UNSUPPORTED = -2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,8 +39,7 @@ object WifiP2pManagerHelper {
|
|||||||
try {
|
try {
|
||||||
setWifiP2pChannels.invoke(this, c, lc, oc, listener)
|
setWifiP2pChannels.invoke(this, c, lc, oc, listener)
|
||||||
} catch (e: NoSuchMethodException) {
|
} catch (e: NoSuchMethodException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
listener.onFailure(UNSUPPORTED)
|
listener.onFailure(UNSUPPORTED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,8 +57,7 @@ object WifiP2pManagerHelper {
|
|||||||
try {
|
try {
|
||||||
startWps.invoke(this, c, wps, listener)
|
startWps.invoke(this, c, wps, listener)
|
||||||
} catch (e: NoSuchMethodException) {
|
} catch (e: NoSuchMethodException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
listener.onFailure(UNSUPPORTED)
|
listener.onFailure(UNSUPPORTED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,8 +76,7 @@ object WifiP2pManagerHelper {
|
|||||||
try {
|
try {
|
||||||
deletePersistentGroup.invoke(this, c, netId, listener)
|
deletePersistentGroup.invoke(this, c, netId, listener)
|
||||||
} catch (e: NoSuchMethodException) {
|
} catch (e: NoSuchMethodException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
listener.onFailure(UNSUPPORTED)
|
listener.onFailure(UNSUPPORTED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,11 +102,11 @@ object WifiP2pManagerHelper {
|
|||||||
val proxy = Proxy.newProxyInstance(interfacePersistentGroupInfoListener.classLoader,
|
val proxy = Proxy.newProxyInstance(interfacePersistentGroupInfoListener.classLoader,
|
||||||
arrayOf(interfacePersistentGroupInfoListener)) { proxy, method, args ->
|
arrayOf(interfacePersistentGroupInfoListener)) { proxy, method, args ->
|
||||||
if (method.name == "onPersistentGroupInfoAvailable") {
|
if (method.name == "onPersistentGroupInfoAvailable") {
|
||||||
if (args.size != 1) Crashlytics.log(Log.WARN, TAG, "Unexpected args: $args")
|
if (args.size != 1) Timber.w("Unexpected args: $args")
|
||||||
listener(getGroupList.invoke(args[0]) as Collection<WifiP2pGroup>)
|
listener(getGroupList.invoke(args[0]) as Collection<WifiP2pGroup>)
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
Crashlytics.log(Log.WARN, TAG, "Unexpected method, calling super: $method")
|
Timber.w("Unexpected method, calling super: $method")
|
||||||
ProxyBuilder.callSuper(proxy, method, args)
|
ProxyBuilder.callSuper(proxy, method, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,9 @@ package be.mygod.vpnhotspot.util
|
|||||||
|
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.HandlerThread
|
import android.os.HandlerThread
|
||||||
import android.util.Log
|
|
||||||
import androidx.core.os.postDelayed
|
import androidx.core.os.postDelayed
|
||||||
import com.crashlytics.android.Crashlytics
|
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
|
import timber.log.Timber
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
@@ -86,11 +85,11 @@ class RootSession : AutoCloseable {
|
|||||||
*/
|
*/
|
||||||
fun submit(command: String) {
|
fun submit(command: String) {
|
||||||
val result = execQuiet(command)
|
val result = execQuiet(command)
|
||||||
if (result.code != 0) Crashlytics.log(Log.VERBOSE, TAG, "$command exited with ${result.code}")
|
if (result.code != 0) Timber.v("$command exited with ${result.code}")
|
||||||
var msg = result.err.joinToString("\n").trim()
|
var msg = result.err.joinToString("\n").trim()
|
||||||
if (msg.isNotEmpty()) Crashlytics.log(Log.VERBOSE, TAG, msg)
|
if (msg.isNotEmpty()) Timber.v(msg)
|
||||||
msg = result.out.joinToString("\n").trim()
|
msg = result.out.joinToString("\n").trim()
|
||||||
if (msg.isNotEmpty()) Crashlytics.log(Log.VERBOSE, TAG, msg)
|
if (msg.isNotEmpty()) Timber.v(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun execQuiet(command: String, redirect: Boolean = false): Shell.Result {
|
fun execQuiet(command: String, redirect: Boolean = false): Shell.Result {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import androidx.databinding.BindingAdapter
|
|||||||
import be.mygod.vpnhotspot.BuildConfig
|
import be.mygod.vpnhotspot.BuildConfig
|
||||||
import be.mygod.vpnhotspot.R
|
import be.mygod.vpnhotspot.R
|
||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
import com.crashlytics.android.Crashlytics
|
import timber.log.Timber
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.net.NetworkInterface
|
import java.net.NetworkInterface
|
||||||
import java.net.SocketException
|
import java.net.SocketException
|
||||||
@@ -28,11 +28,6 @@ fun Long.toPluralInt(): Int {
|
|||||||
|
|
||||||
fun CharSequence?.onEmpty(otherwise: CharSequence): CharSequence = if (isNullOrEmpty()) otherwise else this!!
|
fun CharSequence?.onEmpty(otherwise: CharSequence): CharSequence = if (isNullOrEmpty()) otherwise else this!!
|
||||||
|
|
||||||
fun debugLog(tag: String?, message: String?) {
|
|
||||||
if (BuildConfig.DEBUG) Log.d(tag, message)
|
|
||||||
Crashlytics.log("$tag: $message")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun broadcastReceiver(receiver: (Context, Intent) -> Unit) = object : BroadcastReceiver() {
|
fun broadcastReceiver(receiver: (Context, Intent) -> Unit) = object : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context, intent: Intent) = receiver(context, intent)
|
override fun onReceive(context: Context, intent: Intent) = receiver(context, intent)
|
||||||
}
|
}
|
||||||
@@ -58,8 +53,7 @@ fun NetworkInterface.formatAddresses() =
|
|||||||
listOfNotNull(try {
|
listOfNotNull(try {
|
||||||
hardwareAddress?.joinToString(":") { "%02x".format(it) }
|
hardwareAddress?.joinToString(":") { "%02x".format(it) }
|
||||||
} catch (e: SocketException) {
|
} catch (e: SocketException) {
|
||||||
e.printStackTrace()
|
Timber.w(e)
|
||||||
Crashlytics.logException(e)
|
|
||||||
null
|
null
|
||||||
}))
|
}))
|
||||||
.joinToString("\n")
|
.joinToString("\n")
|
||||||
@@ -85,7 +79,7 @@ fun thread(name: String? = null, start: Boolean = true, isDaemon: Boolean = fals
|
|||||||
val thread = kotlin.concurrent.thread(false, isDaemon, contextClassLoader, name, priority, block)
|
val thread = kotlin.concurrent.thread(false, isDaemon, contextClassLoader, name, priority, block)
|
||||||
thread.setUncaughtExceptionHandler { _, e ->
|
thread.setUncaughtExceptionHandler { _, e ->
|
||||||
SmartSnackbar.make(R.string.noisy_su_failure).show()
|
SmartSnackbar.make(R.string.noisy_su_failure).show()
|
||||||
Crashlytics.logException(e)
|
Timber.w(e)
|
||||||
}
|
}
|
||||||
if (start) thread.start()
|
if (start) thread.start()
|
||||||
return thread
|
return thread
|
||||||
|
|||||||
@@ -7,21 +7,25 @@
|
|||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:isScrollContainer="true"
|
android:isScrollContainer="true"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="16dp">
|
android:padding="16dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:text="@string/donations__description"
|
android:text="@string/donations__description"
|
||||||
android:textAppearance="@android:style/TextAppearance.Small" />
|
android:textAppearance="@android:style/TextAppearance.Small" />
|
||||||
<LinearLayout android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
<LinearLayout
|
||||||
android:orientation="vertical" >
|
android:id="@+id/donations__google"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@@ -60,10 +64,12 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<ViewStub
|
<ViewStub
|
||||||
android:id="@+id/donations__more_stub"
|
android:id="@+id/donations__more_stub"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout="@layout/fragment_ebeg_more" />
|
android:layout="@layout/fragment_ebeg_more" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|||||||
Reference in New Issue
Block a user