Loading app/build.gradle +5 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,8 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } dataBinding.enabled = true flavorDimensions "distribution" productFlavors { standard { Loading Loading @@ -82,6 +84,9 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.fragment:fragment:1.0.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' implementation 'androidx.lifecycle:lifecycle-livedata:2.0.0' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.0.0' implementation 'androidx.preference:preference:1.0.0' implementation 'com.google.android.material:material:1.0.0' Loading app/src/main/java/at/bitfire/davdroid/ui/DebugInfoActivity.kt +181 −200 Original line number Diff line number Diff line Loading @@ -11,7 +11,7 @@ package at.bitfire.davdroid.ui import android.Manifest import android.accounts.Account import android.accounts.AccountManager import android.app.Activity import android.app.Application import android.content.ContentResolver import android.content.ContentUris import android.content.Context Loading @@ -32,26 +32,28 @@ import androidx.core.app.ShareCompat import androidx.core.content.ContextCompat import androidx.core.content.FileProvider import androidx.core.content.pm.PackageInfoCompat import androidx.loader.app.LoaderManager import androidx.loader.content.AsyncTaskLoader import androidx.loader.content.Loader import androidx.databinding.DataBindingUtil import androidx.databinding.ObservableField import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.ViewModelProviders import at.bitfire.dav4jvm.exception.HttpException import at.bitfire.davdroid.BuildConfig import at.bitfire.davdroid.InvalidAccountException import at.bitfire.davdroid.R import at.bitfire.davdroid.databinding.ActivityDebugInfoBinding import at.bitfire.davdroid.log.Logger import at.bitfire.davdroid.model.ServiceDB import at.bitfire.davdroid.resource.LocalAddressBook import at.bitfire.davdroid.settings.AccountSettings import at.bitfire.ical4android.TaskProvider import kotlinx.android.synthetic.main.activity_debug_info.* import org.dmfs.tasks.contract.TaskContract import java.io.File import java.io.FileWriter import java.io.IOException import java.util.logging.Level import kotlin.concurrent.thread class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<String> { class DebugInfoActivity: AppCompatActivity() { companion object { const val KEY_THROWABLE = "throwable" Loading @@ -63,13 +65,17 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri const val KEY_REMOTE_RESOURCE = "remoteResource" } private var report: String? = null private lateinit var model: ReportModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_debug_info) LoaderManager.getInstance(this).initLoader(0, intent.extras, this) model = ViewModelProviders.of(this).get(ReportModel::class.java) if (savedInstanceState == null) model.generateReport(intent.extras) val binding = DataBindingUtil.setContentView<ActivityDebugInfoBinding>(this, R.layout.activity_debug_info) binding.model = model } override fun onCreateOptionsMenu(menu: Menu): Boolean { Loading @@ -79,7 +85,7 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri fun onShare(item: MenuItem) { report?.let { model.report.get()?.let { report -> val builder = ShareCompat.IntentBuilder.from(this) .setSubject("${getString(R.string.app_name)} ${BuildConfig.VERSION_NAME} debug info") .setType("text/plain") Loading @@ -92,14 +98,14 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri val reportFile = File(debugInfoDir, "davx5-info.txt") Logger.log.fine("Writing debug info to ${reportFile.absolutePath}") val writer = FileWriter(reportFile) writer.write(it) writer.write(report) writer.close() builder.setStream(FileProvider.getUriForFile(this, getString(R.string.authority_debug_provider), reportFile)) builder.intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK) } catch(e: IOException) { // creating an attachment failed, so send it inline val text = "Couldn't create debug info file: " + Log.getStackTraceString(e) + "\n\n$it" val text = "Couldn't create debug info file: " + Log.getStackTraceString(e) + "\n\n$report" builder.setText(text) } Loading @@ -108,84 +114,61 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri } override fun onCreateLoader(id: Int, args: Bundle?) = ReportLoader(this, args) override fun onLoadFinished(loader: Loader<String>, data: String?) { data?.let { report = it text_report.text = it text_report.setTextIsSelectable(true) } } override fun onLoaderReset(loader: Loader<String>) {} class ReportModel(application: Application): AndroidViewModel(application) { class ReportLoader( val activity: Activity, val extras: Bundle? ): AsyncTaskLoader<String>(activity) { val report = ObservableField<String>() var result: String? = null override fun onStartLoading() { if (result != null) deliverResult(result) else forceLoad() } override fun loadInBackground(): String { Logger.log.info("Building debug info") val report = StringBuilder("--- BEGIN DEBUG INFO ---\n") fun generateReport(extras: Bundle?) { Logger.log.info("Generating debug info report") thread { val context = getApplication<Application>() val text = StringBuilder("--- BEGIN DEBUG INFO ---\n") // begin with most specific information extras?.getInt(KEY_PHASE, -1).takeIf { it != -1 }?.let { report.append("SYNCHRONIZATION INFO\nSynchronization phase: $it\n") text.append("SYNCHRONIZATION INFO\nSynchronization phase: $it\n") } extras?.getParcelable<Account>(KEY_ACCOUNT)?.let { report.append("Account name: ${it.name}\n") text.append("Account name: ${it.name}\n") } extras?.getString(KEY_AUTHORITY)?.let { report.append("Authority: $it\n") text.append("Authority: $it\n") } // exception details val throwable = extras?.getSerializable(KEY_THROWABLE) as Throwable? if (throwable is HttpException) { throwable.request?.let { report.append("\nHTTP REQUEST:\n$it\n") throwable.requestBody?.let { report.append(it) } report.append("\n\n") text.append("\nHTTP REQUEST:\n$it\n") throwable.requestBody?.let { text.append(it) } text.append("\n\n") } throwable.response?.let { report.append("HTTP RESPONSE:\n$it\n") throwable.responseBody?.let { report.append(it) } report.append("\n\n") text.append("HTTP RESPONSE:\n$it\n") throwable.responseBody?.let { text.append(it) } text.append("\n\n") } } extras?.getString(KEY_LOCAL_RESOURCE)?.let { report.append("\nLOCAL RESOURCE:\n$it\n") text.append("\nLOCAL RESOURCE:\n$it\n") } extras?.getString(KEY_REMOTE_RESOURCE)?.let { report.append("\nREMOTE RESOURCE:\n$it\n") text.append("\nREMOTE RESOURCE:\n$it\n") } throwable?.let { report.append("\nEXCEPTION:\n${Log.getStackTraceString(throwable)}") text.append("\nEXCEPTION:\n${Log.getStackTraceString(throwable)}") } // logs (for instance, from failed resource detection) extras?.getString(KEY_LOGS)?.let { report.append("\nLOGS:\n$it\n") text.append("\nLOGS:\n$it\n") } // software information try { report.append("\nSOFTWARE INFORMATION\n") text.append("\nSOFTWARE INFORMATION\n") val pm = context.packageManager val appIDs = mutableSetOf( // we always want info about these packages BuildConfig.APPLICATION_ID, // DAVx5 Loading @@ -205,19 +188,19 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri for (appID in appIDs) try { val info = pm.getPackageInfo(appID, 0) report .append("* ").append(appID) text .append("* ").append(appID) .append(" ").append(info.versionName) .append(" (").append(PackageInfoCompat.getLongVersionCode(info)).append(")") pm.getInstallerPackageName(appID)?.let { installer -> report.append(" from ").append(installer) text.append(" from ").append(installer) } info.applicationInfo?.let { applicationInfo -> if (!applicationInfo.enabled) report.append(" disabled!") text.append(" disabled!") if (applicationInfo.flags.and(ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) report.append(" on external storage!") text.append(" on external storage!") } report.append("\n") text.append("\n") } catch(e: PackageManager.NameNotFoundException) { } } catch(e: Exception) { Loading @@ -225,7 +208,7 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri } // connectivity report.append("\nCONNECTIVITY (at the moment)\n") text.append("\nCONNECTIVITY (at the moment)\n") val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager connectivityManager.activeNetworkInfo?.let { networkInfo -> val type = when (networkInfo.type) { Loading @@ -233,19 +216,19 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri ConnectivityManager.TYPE_MOBILE -> "mobile" else -> "type: ${networkInfo.type}" } report.append("Active connection: $type, ${networkInfo.detailedState}\n") text.append("Active connection: $type, ${networkInfo.detailedState}\n") } if (Build.VERSION.SDK_INT >= 23) connectivityManager.defaultProxy?.let { proxy -> report.append("System default proxy: ${proxy.host}:${proxy.port}") text.append("System default proxy: ${proxy.host}:${proxy.port}") } report.append("\n") text.append("\n") report.append("CONFIGURATION\n") text.append("CONFIGURATION\n") // power saving val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager if (Build.VERSION.SDK_INT >= 23) report.append("Power saving disabled: ") text.append("Power saving disabled: ") .append(if (powerManager.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)) "yes" else "no") .append("\n") // permissions Loading @@ -253,7 +236,7 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR, TaskProvider.PERMISSION_READ_TASKS, TaskProvider.PERMISSION_WRITE_TASKS, Manifest.permission.ACCESS_COARSE_LOCATION)) { report .append(permission).append(": ") text .append(permission).append(": ") .append(if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) "granted" else Loading @@ -261,7 +244,7 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri .append("\n") } // system-wide sync settings report.append("System-wide synchronization: ") text.append("System-wide synchronization: ") .append(if (ContentResolver.getMasterSyncAutomatically()) "automatically" else "manually") .append("\n") // main accounts Loading @@ -269,43 +252,43 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri for (acct in accountManager.getAccountsByType(context.getString(R.string.account_type))) try { val accountSettings = AccountSettings(context, acct) report.append("Account: ${acct.name}\n" + text.append("Account: ${acct.name}\n" + " Address book sync. interval: ${syncStatus(accountSettings, context.getString(R.string.address_books_authority))}\n" + " Calendar sync. interval: ${syncStatus(accountSettings, CalendarContract.AUTHORITY)}\n" + " OpenTasks sync. interval: ${syncStatus(accountSettings, TaskProvider.ProviderName.OpenTasks.authority)}\n" + " WiFi only: ").append(accountSettings.getSyncWifiOnly()) accountSettings.getSyncWifiOnlySSIDs()?.let { report.append(", SSIDs: ${accountSettings.getSyncWifiOnlySSIDs()}") text.append(", SSIDs: ${accountSettings.getSyncWifiOnlySSIDs()}") } report.append("\n [CardDAV] Contact group method: ${accountSettings.getGroupMethod()}") text.append("\n [CardDAV] Contact group method: ${accountSettings.getGroupMethod()}") .append("\n [CalDAV] Time range (past days): ${accountSettings.getTimeRangePastDays()}") .append("\n Manage calendar colors: ${accountSettings.getManageCalendarColors()}") .append("\n Use event colors: ${accountSettings.getEventColors()}") .append("\n") } catch (e: InvalidAccountException) { report.append("$acct is invalid (unsupported settings version) or does not exist\n") text.append("$acct is invalid (unsupported settings version) or does not exist\n") } // address book accounts for (acct in accountManager.getAccountsByType(context.getString(R.string.account_type_address_book))) try { val addressBook = LocalAddressBook(context, acct, null) report.append("Address book account: ${acct.name}\n" + text.append("Address book account: ${acct.name}\n" + " Main account: ${addressBook.mainAccount}\n" + " URL: ${addressBook.url}\n" + " Sync automatically: ").append(ContentResolver.getSyncAutomatically(acct, ContactsContract.AUTHORITY)).append("\n") } catch(e: Exception) { report.append("$acct is invalid: ${e.message}\n") text.append("$acct is invalid: ${e.message}\n") } report.append("\n") text.append("\n") ServiceDB.OpenHelper(context).use { dbHelper -> report.append("SQLITE DUMP\n") dbHelper.dump(report) report.append("\n") text.append("SQLITE DUMP\n") dbHelper.dump(text) text.append("\n") } try { report.append( text.append( "SYSTEM INFORMATION\n" + "Android version: ${Build.VERSION.RELEASE} (${Build.DISPLAY})\n" + "Device: ${Build.MANUFACTURER} ${Build.MODEL} (${Build.DEVICE})\n\n" Loading @@ -314,11 +297,8 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri Logger.log.log(Level.SEVERE, "Couldn't get system details", e) } report.append("--- END DEBUG INFO ---\n") report.toString().let { result = it return it text.append("--- END DEBUG INFO ---\n") report.set(text.toString()) } } Loading @@ -329,6 +309,7 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri } else "—" } } } app/src/main/res/layout/activity_debug_info.xml +21 −13 Original line number Diff line number Diff line Loading @@ -7,8 +7,14 @@ ~ http://www.gnu.org/licenses/gpl.html --> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="model" type="at.bitfire.davdroid.ui.DebugInfoActivity.ReportModel"/> </data> <ScrollView android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp"> Loading @@ -18,7 +24,9 @@ android:layout_height="wrap_content" android:typeface="monospace" android:fontFamily="monospace" android:text="@string/please_wait" android:text="@{model.report ?? @string/please_wait}" android:textIsSelectable="true" android:id="@+id/text_report"/> </ScrollView> </layout> No newline at end of file Loading
app/build.gradle +5 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,8 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } dataBinding.enabled = true flavorDimensions "distribution" productFlavors { standard { Loading Loading @@ -82,6 +84,9 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.fragment:fragment:1.0.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' implementation 'androidx.lifecycle:lifecycle-livedata:2.0.0' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.0.0' implementation 'androidx.preference:preference:1.0.0' implementation 'com.google.android.material:material:1.0.0' Loading
app/src/main/java/at/bitfire/davdroid/ui/DebugInfoActivity.kt +181 −200 Original line number Diff line number Diff line Loading @@ -11,7 +11,7 @@ package at.bitfire.davdroid.ui import android.Manifest import android.accounts.Account import android.accounts.AccountManager import android.app.Activity import android.app.Application import android.content.ContentResolver import android.content.ContentUris import android.content.Context Loading @@ -32,26 +32,28 @@ import androidx.core.app.ShareCompat import androidx.core.content.ContextCompat import androidx.core.content.FileProvider import androidx.core.content.pm.PackageInfoCompat import androidx.loader.app.LoaderManager import androidx.loader.content.AsyncTaskLoader import androidx.loader.content.Loader import androidx.databinding.DataBindingUtil import androidx.databinding.ObservableField import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.ViewModelProviders import at.bitfire.dav4jvm.exception.HttpException import at.bitfire.davdroid.BuildConfig import at.bitfire.davdroid.InvalidAccountException import at.bitfire.davdroid.R import at.bitfire.davdroid.databinding.ActivityDebugInfoBinding import at.bitfire.davdroid.log.Logger import at.bitfire.davdroid.model.ServiceDB import at.bitfire.davdroid.resource.LocalAddressBook import at.bitfire.davdroid.settings.AccountSettings import at.bitfire.ical4android.TaskProvider import kotlinx.android.synthetic.main.activity_debug_info.* import org.dmfs.tasks.contract.TaskContract import java.io.File import java.io.FileWriter import java.io.IOException import java.util.logging.Level import kotlin.concurrent.thread class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<String> { class DebugInfoActivity: AppCompatActivity() { companion object { const val KEY_THROWABLE = "throwable" Loading @@ -63,13 +65,17 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri const val KEY_REMOTE_RESOURCE = "remoteResource" } private var report: String? = null private lateinit var model: ReportModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_debug_info) LoaderManager.getInstance(this).initLoader(0, intent.extras, this) model = ViewModelProviders.of(this).get(ReportModel::class.java) if (savedInstanceState == null) model.generateReport(intent.extras) val binding = DataBindingUtil.setContentView<ActivityDebugInfoBinding>(this, R.layout.activity_debug_info) binding.model = model } override fun onCreateOptionsMenu(menu: Menu): Boolean { Loading @@ -79,7 +85,7 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri fun onShare(item: MenuItem) { report?.let { model.report.get()?.let { report -> val builder = ShareCompat.IntentBuilder.from(this) .setSubject("${getString(R.string.app_name)} ${BuildConfig.VERSION_NAME} debug info") .setType("text/plain") Loading @@ -92,14 +98,14 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri val reportFile = File(debugInfoDir, "davx5-info.txt") Logger.log.fine("Writing debug info to ${reportFile.absolutePath}") val writer = FileWriter(reportFile) writer.write(it) writer.write(report) writer.close() builder.setStream(FileProvider.getUriForFile(this, getString(R.string.authority_debug_provider), reportFile)) builder.intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK) } catch(e: IOException) { // creating an attachment failed, so send it inline val text = "Couldn't create debug info file: " + Log.getStackTraceString(e) + "\n\n$it" val text = "Couldn't create debug info file: " + Log.getStackTraceString(e) + "\n\n$report" builder.setText(text) } Loading @@ -108,84 +114,61 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri } override fun onCreateLoader(id: Int, args: Bundle?) = ReportLoader(this, args) override fun onLoadFinished(loader: Loader<String>, data: String?) { data?.let { report = it text_report.text = it text_report.setTextIsSelectable(true) } } override fun onLoaderReset(loader: Loader<String>) {} class ReportModel(application: Application): AndroidViewModel(application) { class ReportLoader( val activity: Activity, val extras: Bundle? ): AsyncTaskLoader<String>(activity) { val report = ObservableField<String>() var result: String? = null override fun onStartLoading() { if (result != null) deliverResult(result) else forceLoad() } override fun loadInBackground(): String { Logger.log.info("Building debug info") val report = StringBuilder("--- BEGIN DEBUG INFO ---\n") fun generateReport(extras: Bundle?) { Logger.log.info("Generating debug info report") thread { val context = getApplication<Application>() val text = StringBuilder("--- BEGIN DEBUG INFO ---\n") // begin with most specific information extras?.getInt(KEY_PHASE, -1).takeIf { it != -1 }?.let { report.append("SYNCHRONIZATION INFO\nSynchronization phase: $it\n") text.append("SYNCHRONIZATION INFO\nSynchronization phase: $it\n") } extras?.getParcelable<Account>(KEY_ACCOUNT)?.let { report.append("Account name: ${it.name}\n") text.append("Account name: ${it.name}\n") } extras?.getString(KEY_AUTHORITY)?.let { report.append("Authority: $it\n") text.append("Authority: $it\n") } // exception details val throwable = extras?.getSerializable(KEY_THROWABLE) as Throwable? if (throwable is HttpException) { throwable.request?.let { report.append("\nHTTP REQUEST:\n$it\n") throwable.requestBody?.let { report.append(it) } report.append("\n\n") text.append("\nHTTP REQUEST:\n$it\n") throwable.requestBody?.let { text.append(it) } text.append("\n\n") } throwable.response?.let { report.append("HTTP RESPONSE:\n$it\n") throwable.responseBody?.let { report.append(it) } report.append("\n\n") text.append("HTTP RESPONSE:\n$it\n") throwable.responseBody?.let { text.append(it) } text.append("\n\n") } } extras?.getString(KEY_LOCAL_RESOURCE)?.let { report.append("\nLOCAL RESOURCE:\n$it\n") text.append("\nLOCAL RESOURCE:\n$it\n") } extras?.getString(KEY_REMOTE_RESOURCE)?.let { report.append("\nREMOTE RESOURCE:\n$it\n") text.append("\nREMOTE RESOURCE:\n$it\n") } throwable?.let { report.append("\nEXCEPTION:\n${Log.getStackTraceString(throwable)}") text.append("\nEXCEPTION:\n${Log.getStackTraceString(throwable)}") } // logs (for instance, from failed resource detection) extras?.getString(KEY_LOGS)?.let { report.append("\nLOGS:\n$it\n") text.append("\nLOGS:\n$it\n") } // software information try { report.append("\nSOFTWARE INFORMATION\n") text.append("\nSOFTWARE INFORMATION\n") val pm = context.packageManager val appIDs = mutableSetOf( // we always want info about these packages BuildConfig.APPLICATION_ID, // DAVx5 Loading @@ -205,19 +188,19 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri for (appID in appIDs) try { val info = pm.getPackageInfo(appID, 0) report .append("* ").append(appID) text .append("* ").append(appID) .append(" ").append(info.versionName) .append(" (").append(PackageInfoCompat.getLongVersionCode(info)).append(")") pm.getInstallerPackageName(appID)?.let { installer -> report.append(" from ").append(installer) text.append(" from ").append(installer) } info.applicationInfo?.let { applicationInfo -> if (!applicationInfo.enabled) report.append(" disabled!") text.append(" disabled!") if (applicationInfo.flags.and(ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) report.append(" on external storage!") text.append(" on external storage!") } report.append("\n") text.append("\n") } catch(e: PackageManager.NameNotFoundException) { } } catch(e: Exception) { Loading @@ -225,7 +208,7 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri } // connectivity report.append("\nCONNECTIVITY (at the moment)\n") text.append("\nCONNECTIVITY (at the moment)\n") val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager connectivityManager.activeNetworkInfo?.let { networkInfo -> val type = when (networkInfo.type) { Loading @@ -233,19 +216,19 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri ConnectivityManager.TYPE_MOBILE -> "mobile" else -> "type: ${networkInfo.type}" } report.append("Active connection: $type, ${networkInfo.detailedState}\n") text.append("Active connection: $type, ${networkInfo.detailedState}\n") } if (Build.VERSION.SDK_INT >= 23) connectivityManager.defaultProxy?.let { proxy -> report.append("System default proxy: ${proxy.host}:${proxy.port}") text.append("System default proxy: ${proxy.host}:${proxy.port}") } report.append("\n") text.append("\n") report.append("CONFIGURATION\n") text.append("CONFIGURATION\n") // power saving val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager if (Build.VERSION.SDK_INT >= 23) report.append("Power saving disabled: ") text.append("Power saving disabled: ") .append(if (powerManager.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)) "yes" else "no") .append("\n") // permissions Loading @@ -253,7 +236,7 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR, TaskProvider.PERMISSION_READ_TASKS, TaskProvider.PERMISSION_WRITE_TASKS, Manifest.permission.ACCESS_COARSE_LOCATION)) { report .append(permission).append(": ") text .append(permission).append(": ") .append(if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) "granted" else Loading @@ -261,7 +244,7 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri .append("\n") } // system-wide sync settings report.append("System-wide synchronization: ") text.append("System-wide synchronization: ") .append(if (ContentResolver.getMasterSyncAutomatically()) "automatically" else "manually") .append("\n") // main accounts Loading @@ -269,43 +252,43 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri for (acct in accountManager.getAccountsByType(context.getString(R.string.account_type))) try { val accountSettings = AccountSettings(context, acct) report.append("Account: ${acct.name}\n" + text.append("Account: ${acct.name}\n" + " Address book sync. interval: ${syncStatus(accountSettings, context.getString(R.string.address_books_authority))}\n" + " Calendar sync. interval: ${syncStatus(accountSettings, CalendarContract.AUTHORITY)}\n" + " OpenTasks sync. interval: ${syncStatus(accountSettings, TaskProvider.ProviderName.OpenTasks.authority)}\n" + " WiFi only: ").append(accountSettings.getSyncWifiOnly()) accountSettings.getSyncWifiOnlySSIDs()?.let { report.append(", SSIDs: ${accountSettings.getSyncWifiOnlySSIDs()}") text.append(", SSIDs: ${accountSettings.getSyncWifiOnlySSIDs()}") } report.append("\n [CardDAV] Contact group method: ${accountSettings.getGroupMethod()}") text.append("\n [CardDAV] Contact group method: ${accountSettings.getGroupMethod()}") .append("\n [CalDAV] Time range (past days): ${accountSettings.getTimeRangePastDays()}") .append("\n Manage calendar colors: ${accountSettings.getManageCalendarColors()}") .append("\n Use event colors: ${accountSettings.getEventColors()}") .append("\n") } catch (e: InvalidAccountException) { report.append("$acct is invalid (unsupported settings version) or does not exist\n") text.append("$acct is invalid (unsupported settings version) or does not exist\n") } // address book accounts for (acct in accountManager.getAccountsByType(context.getString(R.string.account_type_address_book))) try { val addressBook = LocalAddressBook(context, acct, null) report.append("Address book account: ${acct.name}\n" + text.append("Address book account: ${acct.name}\n" + " Main account: ${addressBook.mainAccount}\n" + " URL: ${addressBook.url}\n" + " Sync automatically: ").append(ContentResolver.getSyncAutomatically(acct, ContactsContract.AUTHORITY)).append("\n") } catch(e: Exception) { report.append("$acct is invalid: ${e.message}\n") text.append("$acct is invalid: ${e.message}\n") } report.append("\n") text.append("\n") ServiceDB.OpenHelper(context).use { dbHelper -> report.append("SQLITE DUMP\n") dbHelper.dump(report) report.append("\n") text.append("SQLITE DUMP\n") dbHelper.dump(text) text.append("\n") } try { report.append( text.append( "SYSTEM INFORMATION\n" + "Android version: ${Build.VERSION.RELEASE} (${Build.DISPLAY})\n" + "Device: ${Build.MANUFACTURER} ${Build.MODEL} (${Build.DEVICE})\n\n" Loading @@ -314,11 +297,8 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri Logger.log.log(Level.SEVERE, "Couldn't get system details", e) } report.append("--- END DEBUG INFO ---\n") report.toString().let { result = it return it text.append("--- END DEBUG INFO ---\n") report.set(text.toString()) } } Loading @@ -329,6 +309,7 @@ class DebugInfoActivity: AppCompatActivity(), LoaderManager.LoaderCallbacks<Stri } else "—" } } }
app/src/main/res/layout/activity_debug_info.xml +21 −13 Original line number Diff line number Diff line Loading @@ -7,8 +7,14 @@ ~ http://www.gnu.org/licenses/gpl.html --> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="model" type="at.bitfire.davdroid.ui.DebugInfoActivity.ReportModel"/> </data> <ScrollView android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp"> Loading @@ -18,7 +24,9 @@ android:layout_height="wrap_content" android:typeface="monospace" android:fontFamily="monospace" android:text="@string/please_wait" android:text="@{model.report ?? @string/please_wait}" android:textIsSelectable="true" android:id="@+id/text_report"/> </ScrollView> </layout> No newline at end of file