Extend sync diagnose

This commit is contained in:
Jonas L 2019-04-29 00:00:00 +00:00
parent e69c5a081b
commit 9d93c19de3
6 changed files with 132 additions and 1 deletions

View file

@ -85,6 +85,10 @@ class SyncUtil (private val logic: AppLogic) {
shouldSyncImportant.or(shouldSyncUnimportant).or(shouldSyncVeryUnimportant)
)
private val lastSyncExceptionInternal = MutableLiveData<Exception?>().apply { postValue(null) }
val lastSyncException = lastSyncExceptionInternal.castDown()
val isSyncing = liveDataFromFunction (pollInterval = 100) { isSyncingLock.isLocked }
init {
runAsync {
wipeCacheIfUpdated()
@ -113,12 +117,15 @@ class SyncUtil (private val logic: AppLogic) {
lastSync.value = logic.timeApi.getCurrentUptimeInMillis()
SyncInBackgroundWorker.deschedule()
lastSyncExceptionInternal.postValue(null)
// wait 2 to 3 seconds before any next sync (debounce)
logic.timeApi.sleep((2 * 1000 + random.nextInt(1000)).toLong())
} catch (ex: Exception) {
// wait 10 to 15 seconds before retrying
lastSyncExceptionInternal.postValue(ex)
if (BuildConfig.DEBUG) {
Log.w(LOG_TAG, "sync failed", ex)
}

View file

@ -0,0 +1,69 @@
/*
* TimeLimit Copyright <C> 2019 Jonas Lochmann
*
* 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 version 3 of the License.
*
* 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 <https://www.gnu.org/licenses/>.
*/
package io.timelimit.android.ui.diagnose
import android.app.Dialog
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import io.timelimit.android.R
import io.timelimit.android.extensions.showSafe
import java.io.PrintWriter
import java.io.StringWriter
class DiagnoseExceptionDialogFragment: DialogFragment() {
companion object {
private const val DIALOG_TAG = "DiagnoseExceptionDialogFragment"
private const val EXCEPTION = "ex"
fun newInstance(exception: Exception) = DiagnoseExceptionDialogFragment().apply {
arguments = Bundle().apply {
putSerializable(EXCEPTION, exception)
}
}
fun getStackTraceString(tr: Throwable): String = StringWriter().let { sw ->
PrintWriter(sw).let { pw ->
tr.printStackTrace(pw)
pw.flush()
}
sw.toString()
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val message = getStackTraceString(arguments!!.getSerializable(EXCEPTION) as Exception)
val clipboard = context!!.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
return AlertDialog.Builder(context!!, theme)
.setMessage(message)
.setNeutralButton(R.string.diagnose_sync_copy_to_clipboard) { _, _ ->
clipboard.primaryClip = ClipData.newPlainText("TimeLimit", message)
Toast.makeText(context, R.string.diagnose_sync_copied_to_clipboard, Toast.LENGTH_SHORT).show()
}
.setPositiveButton(R.string.generic_ok, null)
.create()
}
fun show(fragmentManager: FragmentManager) = showSafe(fragmentManager, DIALOG_TAG)
}

View file

@ -28,6 +28,8 @@ import androidx.recyclerview.widget.LinearLayoutManager
import io.timelimit.android.R
import io.timelimit.android.async.Threads
import io.timelimit.android.databinding.DiagnoseSyncFragmentBinding
import io.timelimit.android.livedata.map
import io.timelimit.android.livedata.switchMap
import io.timelimit.android.logic.DefaultAppLogic
import io.timelimit.android.sync.actions.apply.UploadActionsUtil
@ -36,6 +38,7 @@ class DiagnoseSyncFragment : Fragment() {
val binding = DiagnoseSyncFragmentBinding.inflate(inflater, container, false)
val logic = DefaultAppLogic.with(context!!)
val adapter = PendingSyncActionAdapter()
val sync = logic.syncUtil
binding.recycler.layoutManager = LinearLayoutManager(context!!)
binding.recycler.adapter = adapter
@ -56,11 +59,31 @@ class DiagnoseSyncFragment : Fragment() {
}
binding.requestSyncBtn.setOnClickListener {
logic.syncUtil.requestImportantSync(true)
sync.requestImportantSync(true)
Toast.makeText(context!!, R.string.diagnose_sync_btn_request_sync_toast, Toast.LENGTH_SHORT).show()
}
sync.isSyncing.switchMap { a ->
sync.lastSyncException.map { b -> a to b }
}.observe(this, Observer { (isSyncing, lastSyncException) ->
binding.hadSyncException = lastSyncException != null
if (isSyncing) {
binding.syncStatusText = getString(R.string.diagnose_sync_status_syncing)
} else if (lastSyncException != null) {
binding.syncStatusText = getString(R.string.diagnose_sync_status_had_error)
} else {
binding.syncStatusText = getString(R.string.diagnose_sync_status_idle)
}
})
binding.showExceptionBtn.setOnClickListener {
sync.lastSyncException.value?.let { ex ->
DiagnoseExceptionDialogFragment.newInstance(ex).show(fragmentManager!!)
}
}
return binding.root
}
}

View file

@ -21,6 +21,14 @@
name="isListEmpty"
type="Boolean" />
<variable
name="syncStatusText"
type="String" />
<variable
name="hadSyncException"
type="boolean" />
<import type="android.view.View" />
</data>
@ -50,6 +58,22 @@
</FrameLayout>
<TextView
android:gravity="center_horizontal"
tools:text="@string/diagnose_sync_status_idle"
android:padding="8dp"
android:textAppearance="?android:textAppearanceMedium"
android:text="@{syncStatusText}"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:visibility="@{hadSyncException ? View.VISIBLE : View.GONE}"
android:id="@+id/show_exception_btn"
android:text="@string/diagnose_sync_btn_show_exception"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/clear_cache_btn"
android:text="@string/diagnose_sync_btn_clear_cache"

View file

@ -43,6 +43,10 @@
<string name="diagnose_sync_btn_clear_cache_toast">Cache geleert</string>
<string name="diagnose_sync_btn_request_sync">Synchronisation anfordern</string>
<string name="diagnose_sync_btn_request_sync_toast">Synchronisation wurde angefordert</string>
<string name="diagnose_sync_btn_show_exception">Fehlerdetails anzeigen</string>
<string name="diagnose_sync_status_idle">Es läuft gerade keine Synchronisation</string>
<string name="diagnose_sync_status_syncing">Es wird jetzt synchronisiert</string>
<string name="diagnose_sync_status_had_error">Es trat ein Fehler beim Synchronisieren auf</string>
<string name="diagnose_fga_title">Erkennung der aktiven App</string>
<string name="diagnose_fga_query_range">Abfragezeitraum</string>

View file

@ -43,6 +43,10 @@
<string name="diagnose_sync_btn_clear_cache_toast">Cache cleared</string>
<string name="diagnose_sync_btn_request_sync">Request sync</string>
<string name="diagnose_sync_btn_request_sync_toast">sync was requested</string>
<string name="diagnose_sync_btn_show_exception">Show exception details</string>
<string name="diagnose_sync_status_idle">Idle</string>
<string name="diagnose_sync_status_syncing">Syncing now</string>
<string name="diagnose_sync_status_had_error">Idle, exception occurred</string>
<string name="diagnose_fga_title">Foreground-App-Detection</string>
<string name="diagnose_fga_query_range">Requested time range</string>