Skip to content
Snippets Groups Projects
Commit 86228484 authored by Pierre Nicolas's avatar Pierre Nicolas :joy: Committed by Adrien Béraud
Browse files

diagnostic: refactor debug window

GitLab: #1468

Change-Id: Ifd8a9ba72b3b53ec51f92c9be8a618d962c01b3e
parent 38e6f43d
No related branches found
No related tags found
No related merge requests found
......@@ -28,11 +28,14 @@ import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.snackbar.Snackbar
import cx.ring.R
......@@ -89,6 +92,9 @@ class LogsActivity : AppCompatActivity() {
}
binding.fab.setOnClickListener { if (disposable == null) startLogging() else stopLogging() }
binding.logRecyclerView.adapter = LogAdapter()
binding.logRecyclerView.layoutManager = LinearLayoutManager(this)
// Check for previous crash reasons, if any.
if (savedInstanceState == null)
showNativeCrashes()
......@@ -124,13 +130,10 @@ class LogsActivity : AppCompatActivity() {
}
private val log: Maybe<String>
get() {
if (mHardwareService.isLogging)
return mHardwareService.startLogs().firstElement()
val log = binding.logView.text
return if (log.isNullOrEmpty()) Maybe.empty()
else Maybe.just(log.toString())
get() = (binding.logRecyclerView.adapter as LogAdapter).getLogs().let {
if (it.isEmpty()) Maybe.empty() else Maybe.just(it)
}
private val logFile: Maybe<File>
get() = log
.observeOn(Schedulers.io())
......@@ -252,12 +255,12 @@ class LogsActivity : AppCompatActivity() {
// Allows to start logging at application startup.
mHardwareService.mPreferenceService.isLogActive = true
binding.logView.text = ""
compositeDisposable.add(mHardwareService.startLogs()
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ message: String ->
binding.logView.text = message
binding.scroll.post { binding.scroll.fullScroll(View.FOCUS_DOWN) }
.subscribe({ messages: List<String> ->
val adapter = binding.logRecyclerView.adapter as LogAdapter
adapter.addLogs(messages.map { LogMessage(it) })
binding.logRecyclerView.smoothScrollToPosition(adapter.itemCount - 1)
}) { e -> Log.w(TAG, "Error in logger", e) }
.apply { disposable = this })
setButtonState(true)
......@@ -291,4 +294,34 @@ class LogsActivity : AppCompatActivity() {
companion object {
private val TAG = LogsActivity::class.simpleName!!
}
}
data class LogMessage(val message: String)
class LogAdapter :
RecyclerView.Adapter<LogAdapter.LogViewHolder>() {
private val logList = mutableListOf<LogMessage>()
fun getLogs(): String = logList.joinToString { it.message }
class LogViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val messageTextView: TextView = itemView.findViewById(R.id.log_item_text)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LogViewHolder =
LogViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.item_log, parent, false)
)
override fun onBindViewHolder(holder: LogViewHolder, position: Int) {
holder.messageTextView.text = logList[position].message
}
override fun getItemCount(): Int = logList.size
fun addLogs(logs: List<LogMessage>) {
logList.addAll(logs)
notifyItemRangeInserted(logList.size - logs.size, logs.size)
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
......@@ -18,36 +19,32 @@
android:layout_height="?attr/actionBarSize"
android:background="@color/background"
tools:menu="@menu/logs_menu"
tools:title="Logs"/>
tools:title="Logs" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/scroll"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:id="@+id/log_view"
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/log_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/padding_medium"
android:textIsSelectable="true"
android:breakStrategy="simple"
android:hyphenationFrequency="none"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:text="@tools:sample/lorem/random" />
</androidx.core.widget.NestedScrollView>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_margin="@dimen/fab_margin"
android:gravity="center"
android:text="@string/pref_logs_start"
app:icon="@drawable/baseline_article_24" />
android:layout_height="0dp"
android:layout_weight="1" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_margin="@dimen/fab_margin"
android:gravity="center"
android:text="@string/pref_logs_start"
app:icon="@drawable/baseline_article_24" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2016-2023 Savoir-faire Linux Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/log_item_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:breakStrategy="simple"
android:hyphenationFrequency="none"
android:paddingHorizontal="@dimen/padding_medium"
android:paddingTop="@dimen/padding_small"
android:textIsSelectable="true"
tools:text="@tools:sample/lorem/random" />
\ No newline at end of file
......@@ -152,7 +152,7 @@ abstract class HardwareService(
abstract fun setDeviceOrientation(rotation: Int)
protected abstract fun videoDevices(): List<String>
private var logs: Observable<String>? = null
private var logs: Observable<List<String>>? = null
private var logEmitter: Emitter<String>? = null
@get:Synchronized
......@@ -160,7 +160,7 @@ abstract class HardwareService(
get() = logs != null
@Synchronized
fun startLogs(): Observable<String> {
fun startLogs(): Observable<List<String>> {
return logs ?: Observable.create { emitter: ObservableEmitter<String> ->
logEmitter = emitter
// Queue the service call on daemon executor to be sure it has been initialized.
......@@ -173,11 +173,8 @@ abstract class HardwareService(
}
}
}
.observeOn(Schedulers.io())
.scan(StringBuffer(1024)) { sb: StringBuffer, message: String -> sb.append(message).append('\n') }
.throttleLatest(500, TimeUnit.MILLISECONDS)
.map { obj: StringBuffer -> obj.toString() }
.replay(1)
.buffer(500, TimeUnit.MILLISECONDS)
.replay()
.autoConnect()
.apply { logs = this }
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment