Make compatible with F-Droid (#42)

* Make compatible with F-Droid
* Fix title bar empty
This commit is contained in:
dwuku
2018-10-02 15:13:12 +00:00
committed by Mygod
parent 5f5bb063c0
commit d131d5d46b
30 changed files with 193 additions and 166 deletions

View File

@@ -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'

View File

@@ -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")
} }
} }

View 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")
}

View 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())
}
}
}

View 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)

View File

@@ -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"/>

View File

@@ -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()
} }

View File

@@ -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()

View File

@@ -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
} }
} }

View File

@@ -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()
} }

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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()
} }

View File

@@ -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
} }

View File

@@ -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)
} }
} }
} }

View File

@@ -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()

View File

@@ -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()
} }
} }

View File

@@ -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 =

View File

@@ -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()
} }
} }

View File

@@ -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
} }

View File

@@ -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() {

View File

@@ -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()
} }
} }

View File

@@ -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)
} }
} }

View File

@@ -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) {

View File

@@ -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"

View File

@@ -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 {

View File

@@ -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)
} }
} }

View File

@@ -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 {

View File

@@ -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

View File

@@ -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>