Skip to content

Commit

Permalink
Hope i finally fixed JNI crashes handling, also improved UI a little
Browse files Browse the repository at this point in the history
  • Loading branch information
F0x1d committed Nov 8, 2022
1 parent 04945e4 commit 071f0f3
Show file tree
Hide file tree
Showing 45 changed files with 366 additions and 223 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ android {
applicationId "com.f0x1d.logfox"
minSdk 21
targetSdk 33
versionCode 20
versionName "1.1.9"
versionCode 21
versionName "1.2.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ import kotlin.system.exitProcess

fun Context.copyText(text: String) = (getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager)
.setPrimaryClip(ClipData.newPlainText(getString(R.string.app_name), text))
.apply {
toast(R.string.text_copied)
}

fun Context.hasPermissionToReadLogs() = ContextCompat.checkSelfPermission(
this,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import com.f0x1d.logfox.databinding.DialogTextBinding
import com.f0x1d.logfox.utils.preferences.AppPreferences
import com.google.android.material.dialog.MaterialAlertDialogBuilder

fun Preference.setupAsEditTextPreference(setup: (DialogTextBinding) -> Unit, get: () -> String?, save: (String?) -> Unit) {
fun Preference.setupAsEditTextPreference(setup: (DialogTextBinding) -> Unit, setupDialog: MaterialAlertDialogBuilder.() -> Unit, get: () -> String?, save: (String?) -> Unit) {
setOnPreferenceClickListener {
val dialogBinding = DialogTextBinding.inflate(LayoutInflater.from(context))
setup.invoke(dialogBinding)
Expand All @@ -22,6 +22,7 @@ fun Preference.setupAsEditTextPreference(setup: (DialogTextBinding) -> Unit, get
save.invoke(dialogBinding.text.text?.toString())
}
.setNegativeButton(android.R.string.cancel, null)
.apply(setupDialog)
.create()
.apply {
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
Expand All @@ -32,7 +33,7 @@ fun Preference.setupAsEditTextPreference(setup: (DialogTextBinding) -> Unit, get
}
}

fun Preference.setupAsListPreference(items: Array<String>, selected: Int, onSelected: (Int) -> Unit) {
fun Preference.setupAsListPreference(setupDialog: MaterialAlertDialogBuilder.() -> Unit, items: Array<String>, selected: Int, onSelected: (Int) -> Unit) {
setOnPreferenceClickListener {
MaterialAlertDialogBuilder(context)
.setTitle(title)
Expand All @@ -41,6 +42,7 @@ fun Preference.setupAsListPreference(items: Array<String>, selected: Int, onSele
onSelected.invoke(which)
}
.setPositiveButton(android.R.string.cancel, null)
.apply(setupDialog)
.show()
return@setOnPreferenceClickListener true
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.f0x1d.logfox.extensions

import android.view.View
import com.google.android.material.snackbar.Snackbar

fun View.snackbar(text: String) = Snackbar.make(this, text, Snackbar.LENGTH_SHORT).show()
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.f0x1d.logfox.extensions

import android.view.View
import android.view.ViewGroup
import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams

fun View.applyTopInsets(view: View) = applyInsets(view) { insets ->
updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = insets.top
}
}

fun View.applyBottomInsets(view: View) = applyInsets(view) { insets ->
updateLayoutParams<ViewGroup.MarginLayoutParams> {
bottomMargin = insets.bottom
}
}

fun View.applyInsets(view: View, block: View.(Insets) -> Unit) {
ViewCompat.setOnApplyWindowInsetsListener(view) { _, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())

block.invoke(this, insets)

windowInsets
}
}
3 changes: 3 additions & 0 deletions app/src/main/java/com/f0x1d/logfox/receiver/CopyReceiver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package com.f0x1d.logfox.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.f0x1d.logfox.R
import com.f0x1d.logfox.extensions.copyText
import com.f0x1d.logfox.extensions.notificationManagerCompat
import com.f0x1d.logfox.extensions.toast

class CopyReceiver: BroadcastReceiver() {

Expand All @@ -15,6 +17,7 @@ class CopyReceiver: BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {
context.copyText(intent.getStringExtra(Intent.EXTRA_TEXT) ?: "")
context.toast(R.string.text_copied)

context.notificationManagerCompat.cancel(
intent.getStringExtra(EXTRA_PACKAGE_NAME),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,16 @@ class JNICrashDetector(collected: suspend (AppCrash) -> Unit): BaseCrashDetector
removeAll { !it.debugTag }
}

private var wasBacktrace = false
private var firstLineTime = 0L

override fun foundFirstLine(line: LogLine) = line.debugTag && line.content == "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***"
override fun foundFirstLine(line: LogLine) = line.firstJNICrashLine.also {
if (it) firstLineTime = System.currentTimeMillis()
}

override fun stillCollecting(line: LogLine): Boolean {
if (line.debugTag && line.content == "backtrace:")
wasBacktrace = true
if (line.firstJNICrashLine) return false

return if (super.stillCollecting(line))
true
else !wasBacktrace
return super.stillCollecting(line) || firstLineTime + 1000 > System.currentTimeMillis()
}

override fun packageFromCollected(lines: List<LogLine>): String {
Expand All @@ -38,6 +37,9 @@ class JNICrashDetector(collected: suspend (AppCrash) -> Unit): BaseCrashDetector
return "???"
}

private val LogLine.firstJNICrashLine
get() = debugTag && content == "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***"

private val LogLine.debugTag
get() = tag.startsWith("DEBUG")
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class CrashDetailsActivity: BaseViewModelActivity<CrashDetailsViewModel, Activit
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

binding.logCard.applyBottomInsets(window.decorView)

binding.toolbar.setNavigationOnClickListener {
onBackPressed()
}
Expand All @@ -58,8 +60,10 @@ class CrashDetailsActivity: BaseViewModelActivity<CrashDetailsViewModel, Activit
}

override fun onEvent(event: Event) {
if (event.type == CrashDetailsViewModel.EVENT_TYPE_COPY_LINK)
if (event.type == CrashDetailsViewModel.EVENT_TYPE_COPY_LINK) {
copyText(event.consume() ?: return)
snackbar(R.string.text_copied)
}
}

private fun setupFor(appCrash: AppCrash) {
Expand All @@ -79,6 +83,7 @@ class CrashDetailsActivity: BaseViewModelActivity<CrashDetailsViewModel, Activit

binding.copyLayout.setOnClickListener {
copyText(appCrash.log)
snackbar(R.string.text_copied)
}

binding.shareLayout.setOnClickListener {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class MainActivity: BaseViewModelActivity<MainViewModel, ActivityMainBinding>(),

if (!hasNotificationsPermission() && !viewModel.askedNotificationsPermission) {
MaterialAlertDialogBuilder(this)
.setIcon(R.drawable.ic_dialog_notification_important)
.setTitle(R.string.no_notification_permission)
.setMessage(R.string.notification_permission_is_required)
.setCancelable(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package com.f0x1d.logfox.ui.activity.base

import android.content.Context
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.view.WindowCompat
import androidx.viewbinding.ViewBinding
import com.f0x1d.logfox.extensions.snackbar
import com.f0x1d.logfox.utils.preferences.AppPreferences
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
Expand All @@ -19,6 +22,8 @@ abstract class BaseActivity<T : ViewBinding>: AppCompatActivity() {
abstract fun inflateBinding(): T?

override fun onCreate(savedInstanceState: Bundle?) {
WindowCompat.setDecorFitsSystemWindows(window, false)

EntryPointAccessors.fromApplication(applicationContext, BaseActivityEntryPoint::class.java).appPreferences().nightTheme.also { nightInt ->
AppCompatDelegate.setDefaultNightMode(if (nightInt != 0) nightInt else AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
Expand All @@ -34,6 +39,12 @@ abstract class BaseActivity<T : ViewBinding>: AppCompatActivity() {
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))
}

protected fun snackbar(text: String) {
findViewById<View>(android.R.id.content).snackbar(text)
}

protected fun snackbar(id: Int) = snackbar(getString(id))
}

@EntryPoint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ abstract class BaseViewModelActivity<T : BaseViewModel, D : ViewBinding>: BaseAc

onEvent(it)
}

viewModel.snackbarEventsData.observe(this) {
if (it.isConsumed) return@observe

snackbar(it.consume<String>()!!)
}
}

open fun onEvent(event: Event) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class FilterBottomSheet: BaseViewModelBottomSheet<FilterViewModel, SheetFilterBi
private fun showFilterDialog() {
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.log_levels)
.setIcon(R.drawable.ic_dialog_list)
.setMultiChoiceItems(LogLevel.values().map { it.name }.toTypedArray(), viewModel.enabledLogLevels.toTypedArray().toBooleanArray()) { dialog, which, checked ->
viewModel.filterLevel(which, checked)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.f0x1d.logfox.databinding.FragmentExtendedCopyBinding
import com.f0x1d.logfox.extensions.applyBottomInsets
import com.f0x1d.logfox.ui.fragment.base.BaseFragment

class ExtendedCopyFragment: BaseFragment<FragmentExtendedCopyBinding>() {
Expand All @@ -18,6 +19,8 @@ class ExtendedCopyFragment: BaseFragment<FragmentExtendedCopyBinding>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

binding.logText.applyBottomInsets(view)

binding.toolbar.setNavigationOnClickListener {
findNavController().popBackStack()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.updatePadding
import androidx.fragment.app.viewModels
import androidx.hilt.navigation.fragment.hiltNavGraphViewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.f0x1d.logfox.R
import com.f0x1d.logfox.adapter.FiltersAdapter
import com.f0x1d.logfox.databinding.FragmentFiltersBinding
import com.f0x1d.logfox.extensions.applyInsets
import com.f0x1d.logfox.extensions.setClickListenerOn
import com.f0x1d.logfox.ui.fragment.base.BaseViewModelFragment
import com.f0x1d.logfox.viewmodel.LogsViewModel
Expand Down Expand Up @@ -45,6 +47,10 @@ class FiltersFragment: BaseViewModelFragment<FiltersViewModel, FragmentFiltersBi
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

binding.filtersRecycler.applyInsets(view) { insets ->
updatePadding(bottom = insets.bottom)
}

binding.toolbar.setOnClickListener { findNavController().popBackStack() }
binding.toolbar.inflateMenu(R.menu.filters_menu)
binding.toolbar.menu.apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,16 +162,20 @@ class LogsFragment: BaseViewModelFragment<LogsViewModel, FragmentLogsBinding>(),

private fun showSelectedDialog() {
if (adapter.selectedItems.isEmpty()) {
requireContext().toast(R.string.nothing_is_selected)
snackbar(R.string.nothing_is_selected)
return
}

MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.selected)
.setIcon(R.drawable.ic_dialog_checklist)
.setItems(intArrayOf(android.R.string.copy, R.string.extended_copy).fillWithStrings(requireContext())) { dialog, which ->
val textToCopy = adapter.selectedItems.joinToString("\n") { it.original }
when (which) {
0 -> requireContext().copyText(textToCopy)
0 -> {
requireContext().copyText(textToCopy)
snackbar(R.string.text_copied)
}
1 -> findNavController().navigate(LogsFragmentDirections.actionLogsFragmentToLogsExtendedCopyFragment(textToCopy))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ import com.f0x1d.logfox.ui.fragment.base.BaseViewModelFragment
import com.f0x1d.logfox.utils.RecyclerViewDivider
import com.f0x1d.logfox.utils.dpToPx
import com.f0x1d.logfox.utils.event.Event
import com.f0x1d.logfox.utils.toDrawable
import com.f0x1d.logfox.utils.toString
import com.f0x1d.logfox.viewmodel.recordings.RecordingsViewModel
import dagger.hilt.android.AndroidEntryPoint

Expand All @@ -43,8 +41,8 @@ class RecordingsFragment: BaseViewModelFragment<RecordingsViewModel, FragmentRec
viewModel.clearRecordings()
}

binding.recordButton.setOnClickListener { viewModel.toggleStartStop() }
binding.pauseButton.setOnClickListener { viewModel.togglePauseResume() }
binding.recordFab.setOnClickListener { viewModel.toggleStartStop() }
binding.pauseFab.setOnClickListener { viewModel.togglePauseResume() }

binding.recordingsRecycler.layoutManager = LinearLayoutManager(requireContext())
binding.recordingsRecycler.addItemDecoration(RecyclerViewDivider(requireContext(), 10.dpToPx.toInt(), 10.dpToPx.toInt()))
Expand All @@ -57,44 +55,30 @@ class RecordingsFragment: BaseViewModelFragment<RecordingsViewModel, FragmentRec
viewModel.recordingStateData.observe(viewLifecycleOwner) {
when (it) {
RecordingState.IDLE -> {
binding.recordButton.apply {
icon = R.drawable.ic_recording.toDrawable(requireContext())
text = R.string.record.toString(requireContext())
}
binding.recordButton.isEnabled = true
binding.pauseButton.visibility = View.GONE
binding.recordFab.setImageResource(R.drawable.ic_recording)
binding.recordFab.isEnabled = true

binding.pauseFab.hide()
}
RecordingState.RECORDING -> {
binding.recordButton.apply {
icon = R.drawable.ic_stop.toDrawable(requireContext())
text = R.string.stop.toString(requireContext())
}
binding.recordButton.isEnabled = true
binding.pauseButton.apply {
icon = R.drawable.ic_pause.toDrawable(requireContext())
text = R.string.pause.toString(requireContext())
}
binding.pauseButton.visibility = View.VISIBLE
binding.recordFab.setImageResource(R.drawable.ic_stop)
binding.recordFab.isEnabled = true

binding.pauseFab.setImageResource(R.drawable.ic_pause)
binding.pauseFab.show()
}
RecordingState.PAUSED -> {
binding.recordButton.apply {
icon = R.drawable.ic_stop.toDrawable(requireContext())
text = R.string.stop.toString(requireContext())
}
binding.recordButton.isEnabled = true
binding.pauseButton.apply {
icon = R.drawable.ic_play.toDrawable(requireContext())
text = R.string.resume.toString(requireContext())
}
binding.pauseButton.visibility = View.VISIBLE
binding.recordFab.setImageResource(R.drawable.ic_stop)
binding.recordFab.isEnabled = true

binding.pauseFab.setImageResource(R.drawable.ic_play)
binding.pauseFab.show()
}
RecordingState.SAVING -> {
binding.recordButton.apply {
icon = R.drawable.ic_recording.toDrawable(requireContext())
text = R.string.record.toString(requireContext())
}
binding.recordButton.isEnabled = false
binding.pauseButton.visibility = View.GONE
binding.recordFab.setImageResource(R.drawable.ic_recording)
binding.recordFab.isEnabled = false

binding.pauseFab.hide()
}
}
}
Expand Down
Loading

0 comments on commit 071f0f3

Please sign in to comment.