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

@@ -14,8 +14,6 @@ import be.mygod.vpnhotspot.room.AppDatabase
import be.mygod.vpnhotspot.util.DeviceStorageApp
import be.mygod.vpnhotspot.util.Event0
import be.mygod.vpnhotspot.util.RootSession
import com.crashlytics.android.Crashlytics
import io.fabric.sdk.android.Fabric
class App : Application() {
companion object {
@@ -33,7 +31,7 @@ class App : Application() {
deviceStorage.moveSharedPreferencesFrom(this, PreferenceManager.getDefaultSharedPreferencesName(this))
deviceStorage.moveDatabaseFrom(this, AppDatabase.DB_NAME)
} else deviceStorage = this
Fabric.with(deviceStorage, Crashlytics())
initTimber()
ServiceNotification.updateNotificationChannels()
}

View File

@@ -1,111 +0,0 @@
package be.mygod.vpnhotspot
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewStub
import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.Spinner
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.core.net.toUri
import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment
import com.android.billingclient.api.*
import com.crashlytics.android.Crashlytics
/**
* Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/java/org/sufficientlysecure/donations/DonationsFragment.java
*/
class EBegFragment : DialogFragment(), PurchasesUpdatedListener, BillingClientStateListener,
SkuDetailsResponseListener, ConsumeResponseListener {
companion object {
private const val TAG = "EBegFragment"
private const val KEY_TITLE = "title"
private const val KEY_MESSAGE = "message"
}
class MessageDialogFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?) = AlertDialog.Builder(requireContext()).apply {
val arguments = arguments!!
setTitle(arguments.getInt(KEY_TITLE, 0))
setMessage(arguments.getInt(KEY_MESSAGE, 0))
setNeutralButton(R.string.donations__button_close, null)
}.create()
}
private lateinit var billingClient: BillingClient
private lateinit var googleSpinner: Spinner
private var skus: MutableList<SkuDetails>? = null
set(value) {
field = value
googleSpinner.apply {
val adapter = ArrayAdapter(context ?: return, android.R.layout.simple_spinner_item,
value?.map { it.price } ?: listOf(""))
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
setAdapter(adapter)
}
}
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)
googleSpinner = view.findViewById(R.id.donations__google_android_market_spinner)
onBillingServiceDisconnected()
view.findViewById<Button>(R.id.donations__google_android_market_donate_button).setOnClickListener {
val sku = skus?.getOrNull(googleSpinner.selectedItemPosition)
if (sku == null) {
openDialog(R.string.donations__google_android_market_not_supported_title,
R.string.donations__google_android_market_not_supported)
} else billingClient.launchBillingFlow(requireActivity(), BillingFlowParams.newBuilder()
.setSku(sku.sku).setType(BillingClient.SkuType.INAPP).build())
}
@Suppress("ConstantConditionIf")
if (BuildConfig.DONATIONS) (view.findViewById<ViewStub>(R.id.donations__more_stub).inflate() as Button)
.setOnClickListener {
(activity as MainActivity).launchUrl("https://mygod.be/donate/".toUri())
}
}
private fun openDialog(@StringRes title: Int, @StringRes message: Int) = MessageDialogFragment().apply {
arguments = bundleOf(Pair(KEY_TITLE, title), Pair(KEY_MESSAGE, message))
}.show(fragmentManager, "MessageDialogFragment")
override fun onBillingServiceDisconnected() {
skus = null
billingClient = BillingClient.newBuilder(context ?: return).setListener(this).build()
.also { it.startConnection(this) }
}
override fun onBillingSetupFinished(responseCode: Int) {
if (responseCode == BillingClient.BillingResponse.OK) {
billingClient.querySkuDetailsAsync(
SkuDetailsParams.newBuilder().apply {
setSkusList(listOf("donate001", "donate002", "donate005", "donate010", "donate020", "donate050",
"donate100", "donate200", "donatemax"))
setType(BillingClient.SkuType.INAPP)
}.build(), this)
} else Crashlytics.log(Log.ERROR, TAG, "onBillingSetupFinished: $responseCode")
}
override fun onSkuDetailsResponse(responseCode: Int, skuDetailsList: MutableList<SkuDetails>?) {
if (responseCode == BillingClient.BillingResponse.OK) skus = skuDetailsList
else Crashlytics.log(Log.ERROR, TAG, "onSkuDetailsResponse: $responseCode")
}
override fun onPurchasesUpdated(responseCode: Int, purchases: MutableList<Purchase>?) {
if (responseCode == BillingClient.BillingResponse.OK && purchases != null) {
// directly consume in-app purchase, so that people can donate multiple times
purchases.forEach { billingClient.consumeAsync(it.purchaseToken, this) }
} else Crashlytics.log(Log.ERROR, TAG, "onPurchasesUpdated: $responseCode")
}
override fun onConsumeResponse(responseCode: Int, purchaseToken: String?) {
if (responseCode == BillingClient.BillingResponse.OK) {
openDialog(R.string.donations__thanks_dialog_title, R.string.donations__thanks_dialog)
dismissAllowingStateLoss()
} else Crashlytics.log(Log.ERROR, TAG, "onConsumeResponse: $responseCode")
}
}

View File

@@ -9,9 +9,8 @@ import be.mygod.vpnhotspot.manage.LocalOnlyHotspotManager
import be.mygod.vpnhotspot.net.IpNeighbourMonitor
import be.mygod.vpnhotspot.net.TetheringManager
import be.mygod.vpnhotspot.util.broadcastReceiver
import be.mygod.vpnhotspot.util.debugLog
import be.mygod.vpnhotspot.widget.SmartSnackbar
import com.crashlytics.android.Crashlytics
import timber.log.Timber
@RequiresApi(26)
class LocalOnlyHotspotService : IpNeighbourMonitoringService() {
@@ -90,23 +89,23 @@ class LocalOnlyHotspotService : IpNeighbourMonitoringService() {
else -> getString(R.string.failure_reason_unknown, reason)
})
SmartSnackbar.make(message).show()
startFailure(if (reason == WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE) null else
StartFailure(message))
if (reason != WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE) {
Timber.i(StartFailure(message))
}
startFailure()
}
}, app.handler)
} catch (e: IllegalStateException) {
e.printStackTrace()
startFailure(e)
} catch (e: SecurityException) {
// assuming IllegalStateException will be thrown only if
// "Caller already has an active LocalOnlyHotspot request"
} catch (_: IllegalStateException) { } catch (e: SecurityException) {
SmartSnackbar.make(e.localizedMessage).show()
e.printStackTrace()
startFailure(e)
Timber.w(e)
startFailure()
}
return START_STICKY
}
private fun startFailure(e: Exception?) {
if (e?.message != "Caller already has an active LocalOnlyHotspot request") Crashlytics.logException(e)
private fun startFailure() {
updateNotification()
ServiceNotification.stopForeground(this@LocalOnlyHotspotService)
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.UpstreamMonitor
import be.mygod.vpnhotspot.widget.SmartSnackbar
import com.crashlytics.android.Crashlytics
import timber.log.Timber
import java.net.InetAddress
import java.net.InterfaceAddress
@@ -57,7 +57,7 @@ class LocalOnlyInterfaceManager(private val owner: Context, val downstream: Stri
}
} catch (e: Exception) {
SmartSnackbar.make(e.localizedMessage).show()
Crashlytics.logException(e)
Timber.w(e)
routing = null
}
}

View File

@@ -20,10 +20,10 @@ import be.mygod.vpnhotspot.databinding.ActivityMainBinding
import be.mygod.vpnhotspot.manage.TetheringFragment
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
import be.mygod.vpnhotspot.widget.SmartSnackbar
import com.crashlytics.android.Crashlytics
import com.google.android.material.bottomnavigation.BottomNavigationMenuView
import com.google.android.material.bottomnavigation.BottomNavigationView
import q.rorbin.badgeview.QBadgeView
import timber.log.Timber
class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemSelectedListener, ServiceConnection {
companion object {
@@ -38,15 +38,14 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
.setToolbarColor(ContextCompat.getColor(this, R.color.colorPrimary))
.build()
}
fun launchUrl(url: Uri) = try {
customTabsIntent.launchUrl(this, url)
} catch (e: ActivityNotFoundException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
SmartSnackbar.make(url.toString()).show()
} catch (e: SecurityException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
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.util.*
import be.mygod.vpnhotspot.widget.SmartSnackbar
import com.crashlytics.android.Crashlytics
import timber.log.Timber
import java.lang.reflect.InvocationTargetException
class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPreferences.OnSharedPreferenceChangeListener {
@@ -33,7 +33,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
enum class Status {
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() {
val service get() = this@RepeaterService
@@ -79,8 +79,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
if (it.size == 1) group = it.single()
}
} catch (e: ReflectiveOperationException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
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)
else -> getString(R.string.failure_reason_unknown, reason)
})
Crashlytics.logException(Failure(result))
Timber.i(Failure(result))
return result
}
@@ -134,9 +133,8 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
p2pManager = getSystemService()!!
onChannelDisconnected()
app.pref.registerOnSharedPreferenceChangeListener(this)
} catch (exc: RuntimeException) {
exc.printStackTrace()
Crashlytics.logException(exc)
} catch (e: RuntimeException) {
Timber.w(e)
}
}
@@ -154,10 +152,8 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
if (oc != 0) {
val message = getString(R.string.repeater_set_oc_failure, e.message)
SmartSnackbar.make(message).show()
Crashlytics.logException(Failure(message))
}
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(Failure(message, e))
} else Timber.w(e)
}
override fun onChannelDisconnected() {
@@ -179,8 +175,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
val out = try {
RootSession.use { it.execOut("dumpsys ${Context.WIFI_P2P_SERVICE}") }
} catch (e: RuntimeException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
startFailure(e.localizedMessage)
return START_NOT_STICKY
}
@@ -197,7 +192,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
it == null -> doStart()
it.isGroupOwner -> if (routingManager == null) doStart(it)
else -> {
Crashlytics.log(Log.INFO, TAG, "Removing old group ($it)")
Timber.i("Removing old group ($it)")
p2pManager.removeGroup(channel, object : WifiP2pManager.ActionListener {
override fun onSuccess() = doStart()
override fun onFailure(reason: Int) {

View File

@@ -7,6 +7,7 @@ import android.os.Bundle
import androidx.core.content.FileProvider
import androidx.core.net.toUri
import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment
import androidx.preference.Preference
import androidx.preference.SwitchPreference
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.util.RootSession
import be.mygod.vpnhotspot.widget.SmartSnackbar
import com.crashlytics.android.Crashlytics
import com.takisoft.preferencex.PreferenceFragmentCompat
import timber.log.Timber
import java.io.File
import java.io.IOException
import java.io.PrintWriter
@@ -39,7 +40,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
Routing.clean()
true
} catch (e: RuntimeException) {
e.printStackTrace()
Timber.d(e)
SmartSnackbar.make(e.localizedMessage).show()
false
}
@@ -58,8 +59,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
try {
Runtime.getRuntime().exec(arrayOf("logcat", "-d")).inputStream.use { it.copyTo(out) }
} catch (e: IOException) {
e.printStackTrace(writer)
Crashlytics.logException(e)
Timber.w(e)
}
writer.write("\n")
writer.flush()
@@ -93,8 +93,8 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
.joinToString("\n").toByteArray())
} catch (e: Exception) {
e.printStackTrace(writer)
Crashlytics.logException(e)
writer.flush()
Timber.i(e)
}
}
}
@@ -111,7 +111,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
true
}
findPreference("misc.donate").setOnPreferenceClickListener {
EBegFragment().show(fragmentManager, "ebeg_fragment")
EBegFragment().apply { setStyle(DialogFragment.STYLE_NO_TITLE, 0) }.show(fragmentManager, "EBegFragment")
true
}
}
@@ -125,8 +125,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
.filter { it.isUp && !it.isLoopback && it.interfaceAddresses.isNotEmpty() }
.map { it.name }.sorted().toList().toTypedArray()
} catch (e: SocketException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
emptyArray<String>()
})))
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.util.broadcastReceiver
import be.mygod.vpnhotspot.widget.SmartSnackbar
import com.crashlytics.android.Crashlytics
import timber.log.Timber
import java.net.InetAddress
class TetheringService : IpNeighbourMonitoringService(), UpstreamMonitor.Callback {
@@ -84,8 +84,7 @@ class TetheringService : IpNeighbourMonitoringService(), UpstreamMonitor.Callbac
}
}
} catch (e: Exception) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
SmartSnackbar.make(e.localizedMessage).show()
iterator.remove()
}

View File

@@ -25,7 +25,7 @@ import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding
import be.mygod.vpnhotspot.net.TetherType
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
import be.mygod.vpnhotspot.util.formatAddresses
import com.crashlytics.android.Crashlytics
import timber.log.Timber
import java.net.NetworkInterface
@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()
try {
view.context.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
} catch (exc: ActivityNotFoundException) {
exc.printStackTrace()
Crashlytics.logException(exc)
} catch (e: ActivityNotFoundException) {
Timber.w(e)
}
return
}

View File

@@ -10,7 +10,7 @@ import androidx.databinding.BaseObservable
import androidx.recyclerview.widget.RecyclerView
import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.databinding.ListitemManageBinding
import com.crashlytics.android.Crashlytics
import timber.log.Timber
object ManageBar : Manager() {
object Data : BaseObservable() {
@@ -51,14 +51,11 @@ object ManageBar : Manager() {
try {
context.startActivity(Intent()
.setClassName("com.android.settings", "com.android.settings.TetherSettings"))
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
} catch (e: ActivityNotFoundException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
} catch (e: SecurityException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(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.formatAddresses
import be.mygod.vpnhotspot.widget.SmartSnackbar
import com.crashlytics.android.Crashlytics
import timber.log.Timber
import java.net.NetworkInterface
import java.net.SocketException
@@ -47,8 +47,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
return try {
NetworkInterface.getByName(p2pInterface ?: return "")?.formatAddresses() ?: ""
} catch (e: SocketException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
""
}
}
@@ -174,8 +173,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
.update(data.getParcelableExtra(WifiP2pDialogFragment.KEY_CONFIGURATION))
app.handler.postDelayed(binder!!::requestGroupUpdate, 1000)
} catch (e: RuntimeException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
SmartSnackbar.make(e.localizedMessage).show()
}
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.wifi.WifiApManager
import be.mygod.vpnhotspot.widget.SmartSnackbar
import com.crashlytics.android.Crashlytics
import timber.log.Timber
import java.io.IOException
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,
"package:${mainActivity.packageName}".toUri()))
return
} catch (exc: ActivityNotFoundException) {
exc.printStackTrace()
Crashlytics.logException(exc)
} catch (e: ActivityNotFoundException) {
Timber.w(e)
}
val started = manager.isStarted
try {
if (started) manager.stop() else manager.start()
} catch (e: IOException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
Toast.makeText(mainActivity, e.localizedMessage, Toast.LENGTH_LONG).show()
ManageBar.start(itemView.context)
} catch (e: InvocationTargetException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
var cause: Throwable? = e
while (cause != null) {
cause = cause.cause
@@ -125,7 +122,7 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
else -> app.getString(R.string.failure_reason_unknown, error)
}
} catch (e: InvocationTargetException) {
Crashlytics.logException(e)
Timber.w(e)
e.localizedMessage
}
}
@@ -171,8 +168,7 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
try {
BluetoothAdapter.getDefaultAdapter()?.getProfileProxy(parent.requireContext(), this, PAN)
} catch (e: SecurityException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
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.util.ServiceForegroundConnector
import be.mygod.vpnhotspot.util.broadcastReceiver
import com.crashlytics.android.Crashlytics
import timber.log.Timber
import java.net.NetworkInterface
import java.net.SocketException
@@ -53,8 +53,7 @@ class TetheringFragment : Fragment(), ServiceConnection {
ifaceLookup = try {
NetworkInterface.getNetworkInterfaces().asSequence().associateBy { it.name }
} catch (e: SocketException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
emptyMap()
}
this@TetheringFragment.enabledTypes =

View File

@@ -4,7 +4,7 @@ import android.util.Log
import be.mygod.vpnhotspot.R
import be.mygod.vpnhotspot.util.thread
import be.mygod.vpnhotspot.widget.SmartSnackbar
import com.crashlytics.android.Crashlytics
import timber.log.Timber
import java.io.IOException
import java.io.InterruptedIOException
import java.util.concurrent.Executors
@@ -25,25 +25,21 @@ abstract class IpMonitor : Runnable {
val process = try {
builder.start()
} catch (e: IOException) {
e.printStackTrace()
Timber.d(e)
return false
}
monitor = process
val err = thread("${javaClass.simpleName}-error") {
try {
process.errorStream.bufferedReader().forEachLine {
Crashlytics.log(Log.ERROR, javaClass.simpleName, it)
}
process.errorStream.bufferedReader().forEachLine { Timber.e(it) }
} catch (_: InterruptedIOException) { } catch (e: IOException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
}
}
try {
process.inputStream.bufferedReader().forEachLine(this::processLine)
} catch (_: InterruptedIOException) { } catch (e: IOException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
}
err.join()
process.waitFor()
@@ -56,8 +52,8 @@ abstract class IpMonitor : Runnable {
// monitor may get rejected by SELinux
if (handleProcess(ProcessBuilder("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")
Crashlytics.logException(MonitorFailure())
Timber.w("Failed to set up monitor, switching to polling")
Timber.i(MonitorFailure())
val pool = Executors.newScheduledThreadPool(1)
pool.scheduleAtFixedRate(this, 1, 1, TimeUnit.SECONDS)
this.pool = pool
@@ -74,8 +70,8 @@ abstract class IpMonitor : Runnable {
thread("${javaClass.simpleName}-flush-error") {
val err = process.errorStream.bufferedReader().readText()
if (err.isNotBlank()) {
Crashlytics.log(Log.ERROR, javaClass.simpleName, err)
Crashlytics.logException(FlushFailure())
Timber.e(err)
Timber.i(FlushFailure())
SmartSnackbar.make(R.string.noisy_su_failure).show()
}
}

View File

@@ -1,8 +1,7 @@
package be.mygod.vpnhotspot.net
import android.util.Log
import be.mygod.vpnhotspot.util.parseNumericAddressNoThrow
import com.crashlytics.android.Crashlytics
import timber.log.Timber
import java.io.File
import java.io.IOException
import java.net.InetAddress
@@ -13,8 +12,6 @@ data class IpNeighbour(val ip: InetAddress, val dev: String, val lladdr: String,
}
companion object {
private const val TAG = "IpNeighbour"
/**
* Parser based on:
* 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? {
val match = parser.matchEntire(line)
if (match == null) {
if (line.isNotEmpty()) Crashlytics.log(Log.WARN, TAG, line)
if (line.isNotEmpty()) Timber.w(line)
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
"NOARP" -> return null // skip
else -> {
Crashlytics.log(Log.WARN, TAG, "Unknown state encountered: ${match.groupValues[10]}")
Timber.w("Unknown state encountered: ${match.groupValues[10]}")
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() }
.toList()
} catch (e: IOException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
}
return arpCache
}

View File

@@ -1,7 +1,7 @@
package be.mygod.vpnhotspot.net
import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.util.debugLog
import be.mygod.vpnhotspot.debugLog
import java.net.InetAddress
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.client.Client
import be.mygod.vpnhotspot.client.ClientMonitorService
import be.mygod.vpnhotspot.debugLog
import be.mygod.vpnhotspot.util.RootSession
import be.mygod.vpnhotspot.util.computeIfAbsentCompat
import be.mygod.vpnhotspot.util.debugLog
import be.mygod.vpnhotspot.util.stopAndUnbind
import be.mygod.vpnhotspot.widget.SmartSnackbar
import com.crashlytics.android.Crashlytics
import timber.log.Timber
import java.net.*
/**
@@ -165,8 +165,7 @@ class Routing(private val owner: Context, val upstream: String?, private val dow
try {
subroutes.computeIfAbsentCompat(ip) { Subroute(ip, client) }
} catch (e: Exception) {
Crashlytics.logException(e)
e.printStackTrace()
Timber.w(e)
SmartSnackbar.make(e.localizedMessage).show()
}
}

View File

@@ -5,11 +5,10 @@ import android.net.ConnectivityManager
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.util.Log
import androidx.annotation.RequiresApi
import be.mygod.vpnhotspot.App.Companion.app
import com.android.dx.stock.ProxyBuilder
import com.crashlytics.android.Crashlytics
import timber.log.Timber
/**
* Heavily based on:
@@ -32,8 +31,6 @@ object TetheringManager {
fun onTetheringFailed() { }
}
private const val TAG = "TetheringManager"
/**
* This is a sticky broadcast since almost forever.
*
@@ -121,7 +118,7 @@ object TetheringManager {
val proxy = ProxyBuilder.forClass(classOnStartTetheringCallback)
.dexCache(app.cacheDir)
.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) {
"onTetheringStarted" -> {
callback.onTetheringStarted()
@@ -132,7 +129,7 @@ object TetheringManager {
null
}
else -> {
Crashlytics.log(Log.WARN, TAG, "Unexpected method, calling super: $method")
Timber.w("Unexpected method, calling super: $method")
ProxyBuilder.callSuper(proxy, method, args)
}
}

View File

@@ -1,7 +1,6 @@
package be.mygod.vpnhotspot.net
import android.os.SystemClock
import android.util.Log
import android.util.LongSparseArray
import be.mygod.vpnhotspot.room.AppDatabase
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.RootSession
import be.mygod.vpnhotspot.util.parseNumericAddress
import com.crashlytics.android.Crashlytics
import timber.log.Timber
import java.net.InetAddress
import java.util.concurrent.TimeUnit
@@ -112,9 +111,8 @@ object TrafficRecorder {
else -> check(false)
}
} catch (e: RuntimeException) {
Crashlytics.log(Log.WARN, TAG, line)
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(line)
Timber.w(e)
}
}
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.NetworkRequest
import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.util.debugLog
import be.mygod.vpnhotspot.debugLog
object VpnMonitor : UpstreamMonitor() {
private const val TAG = "VpnMonitor"

View File

@@ -4,10 +4,9 @@ import android.net.wifi.WifiConfiguration
import android.os.Build
import android.os.Parcel
import android.os.Parcelable
import android.util.Log
import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.util.RootSession
import com.crashlytics.android.Crashlytics
import timber.log.Timber
import java.io.File
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 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
* Android's results instead.
@@ -55,9 +53,8 @@ class P2pSupplicantConfiguration(private val initContent: String? = null) : Parc
} catch (e: NoSuchElementException) {
null
} catch (e: RuntimeException) {
if (contentDelegate.isInitialized()) Crashlytics.log(Log.WARN, TAG, content)
e.printStackTrace()
Crashlytics.logException(e)
if (contentDelegate.isInitialized()) Timber.w(content)
Timber.w(e)
null
}
}
@@ -82,9 +79,9 @@ class P2pSupplicantConfiguration(private val initContent: String? = null) : Parc
})
}
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()
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
RootSession.use {

View File

@@ -4,14 +4,12 @@ import android.annotation.SuppressLint
import android.net.wifi.WpsInfo
import android.net.wifi.p2p.WifiP2pGroup
import android.net.wifi.p2p.WifiP2pManager
import android.util.Log
import com.android.dx.stock.ProxyBuilder
import com.crashlytics.android.Crashlytics
import timber.log.Timber
import java.lang.reflect.Proxy
import java.util.regex.Pattern
object WifiP2pManagerHelper {
private const val TAG = "WifiP2pManagerHelper"
const val UNSUPPORTED = -2
/**
@@ -41,8 +39,7 @@ object WifiP2pManagerHelper {
try {
setWifiP2pChannels.invoke(this, c, lc, oc, listener)
} catch (e: NoSuchMethodException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
listener.onFailure(UNSUPPORTED)
}
}
@@ -60,8 +57,7 @@ object WifiP2pManagerHelper {
try {
startWps.invoke(this, c, wps, listener)
} catch (e: NoSuchMethodException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
listener.onFailure(UNSUPPORTED)
}
}
@@ -80,8 +76,7 @@ object WifiP2pManagerHelper {
try {
deletePersistentGroup.invoke(this, c, netId, listener)
} catch (e: NoSuchMethodException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
listener.onFailure(UNSUPPORTED)
}
}
@@ -107,11 +102,11 @@ object WifiP2pManagerHelper {
val proxy = Proxy.newProxyInstance(interfacePersistentGroupInfoListener.classLoader,
arrayOf(interfacePersistentGroupInfoListener)) { proxy, method, args ->
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>)
null
} else {
Crashlytics.log(Log.WARN, TAG, "Unexpected method, calling super: $method")
Timber.w("Unexpected method, calling super: $method")
ProxyBuilder.callSuper(proxy, method, args)
}
}

View File

@@ -2,10 +2,9 @@ package be.mygod.vpnhotspot.util
import android.os.Handler
import android.os.HandlerThread
import android.util.Log
import androidx.core.os.postDelayed
import com.crashlytics.android.Crashlytics
import com.topjohnwu.superuser.Shell
import timber.log.Timber
import java.util.*
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.ReentrantLock
@@ -86,11 +85,11 @@ class RootSession : AutoCloseable {
*/
fun submit(command: String) {
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()
if (msg.isNotEmpty()) Crashlytics.log(Log.VERBOSE, TAG, msg)
if (msg.isNotEmpty()) Timber.v(msg)
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 {

View File

@@ -11,7 +11,7 @@ import androidx.databinding.BindingAdapter
import be.mygod.vpnhotspot.BuildConfig
import be.mygod.vpnhotspot.R
import be.mygod.vpnhotspot.widget.SmartSnackbar
import com.crashlytics.android.Crashlytics
import timber.log.Timber
import java.net.InetAddress
import java.net.NetworkInterface
import java.net.SocketException
@@ -28,11 +28,6 @@ fun Long.toPluralInt(): Int {
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() {
override fun onReceive(context: Context, intent: Intent) = receiver(context, intent)
}
@@ -58,8 +53,7 @@ fun NetworkInterface.formatAddresses() =
listOfNotNull(try {
hardwareAddress?.joinToString(":") { "%02x".format(it) }
} catch (e: SocketException) {
e.printStackTrace()
Crashlytics.logException(e)
Timber.w(e)
null
}))
.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)
thread.setUncaughtExceptionHandler { _, e ->
SmartSnackbar.make(R.string.noisy_su_failure).show()
Crashlytics.logException(e)
Timber.w(e)
}
if (start) thread.start()
return thread