Commit c71dc2ba authored by Ricki Hirner's avatar Ricki Hirner 🐑

New DebugInfoActivity

* DebugInfoActivity shows and allows to share sync exceptions
* log sync phase
parent c90a3401
......@@ -18,8 +18,8 @@ android {
minSdkVersion 14
targetSdkVersion 23
versionCode 73
versionName "0.9-alpha1"
versionCode 74
versionName "0.9-alpha2"
buildConfigField "java.util.Date", "buildTime", "new java.util.Date()"
}
......
......@@ -86,6 +86,10 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.DebugInfoActivity"
android:label="@string/debug_info_title">
</activity>
<activity
android:name=".ui.setup.AddAccountActivity"
android:excludeFromRecents="true" >
......
/*
* Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid.ui;
import android.accounts.Account;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import java.io.PrintWriter;
import java.io.StringWriter;
import at.bitfire.dav4android.exception.HttpException;
import at.bitfire.davdroid.BuildConfig;
import at.bitfire.davdroid.Constants;
import at.bitfire.davdroid.R;
import lombok.Cleanup;
public class DebugInfoActivity extends Activity {
public static final String
KEY_EXCEPTION = "exception",
KEY_ACCOUNT = "account",
KEY_PHASE = "phase";
private static final String APP_ID = "at.bitfire.davdroid";
String report;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.debug_info_activity);
TextView tvReport = (TextView)findViewById(R.id.text_report);
tvReport.setText(generateReport(getIntent().getExtras()));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.exception_details_activity, menu);
return true;
}
public void onShare(MenuItem item) {
if (!TextUtils.isEmpty(report)) {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, "DAVdroid Exception Details");
sendIntent.putExtra(Intent.EXTRA_TEXT, report);
sendIntent.setType("text/plain");
startActivity(sendIntent);
}
}
protected String generateReport(Bundle extras) {
Exception exception = null;
Account account = null;
Integer phase = null;
if (extras != null) {
exception = (Exception) extras.getSerializable(KEY_EXCEPTION);
account = (Account) extras.getParcelable(KEY_ACCOUNT);
phase = extras.getInt(KEY_PHASE);
}
StringBuilder report = new StringBuilder();
try {
report.append(
"SYSTEM INFORMATION\n" +
"Android version: " + Build.VERSION.RELEASE + " (" + Build.DISPLAY + ")\n" +
"Device: " + Build.MANUFACTURER + " / " + Build.MODEL + " (" + Build.DEVICE + ")\n\n"
);
} catch (Exception ex) {
Constants.log.error("Couldn't get system details", ex);
}
try {
PackageManager pm = getPackageManager();
String installedFrom = pm.getInstallerPackageName("at.bitfire.davdroid");
if (TextUtils.isEmpty(installedFrom))
installedFrom = "APK (directly)";
else {
PackageInfo installer = pm.getPackageInfo(installedFrom, PackageManager.GET_META_DATA);
if (installer != null)
installedFrom = pm.getApplicationLabel(installer.applicationInfo).toString();
}
report.append(
"SOFTWARE INFORMATION\n" +
"DAVdroid version: " + BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ") " + BuildConfig.buildTime.toString() + "\n" +
"Installed from: " + installedFrom + "\n\n"
);
} catch(Exception ex) {
Constants.log.error("Couldn't get software information", ex);
}
report.append(
"CONFIGURATION\n" +
"System-wide synchronization: " + (ContentResolver.getMasterSyncAutomatically() ? "automatically" : "manually") + " (overrides account settings)\n"
);
if (account != null)
report.append(
"Account name: " + account.name + "\n" +
"Address book synchronization: " + syncStatus(account, ContactsContract.AUTHORITY) + "\n" +
"Calendar synchronization: " + syncStatus(account, CalendarContract.AUTHORITY) + "\n" +
"OpenTasks synchronization: " + syncStatus(account, "org.dmfs.tasks") + "\n\n"
);
if (phase != null) {
report.append("SYNCHRONIZATION INFO\nSychronization phase: " + phase + "\n\n");
}
if (exception instanceof HttpException) {
HttpException http = (HttpException)exception;
if (http.request != null)
report.append("HTTP REQUEST:\n" + http.request + "\n\n");
if (http.response != null)
report.append("HTTP RESPONSE:\n" + http.response + "\n\n");
}
if (exception != null) {
report.append("STACK TRACE\n");
StringWriter writer = new StringWriter();
@Cleanup PrintWriter printWriter = new PrintWriter(writer);
exception.printStackTrace(printWriter);
report.append(writer.toString());
}
return report.toString();
}
protected static String syncStatus(Account account, String authority) {
return ContentResolver.getIsSyncable(account, authority) > 0 ?
(ContentResolver.getSyncAutomatically(account, ContactsContract.AUTHORITY) ? "automatically" : "manually") :
"—";
}
}
......@@ -11,6 +11,7 @@ import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Debug;
import android.provider.Settings;
import android.text.Html;
import android.text.method.LinkMovementMethod;
......@@ -58,6 +59,10 @@ public class MainActivity extends Activity {
startActivity(new Intent(this, AddAccountActivity.class));
}
public void showDebugInfo(MenuItem item) {
startActivity(new Intent(this, DebugInfoActivity.class));
}
public void showSettings(MenuItem item) {
startActivity(new Intent(this, SettingsActivity.class));
}
......
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering).
~ All rights reserved. This program and the accompanying materials
~ are made available under the terms of the GNU Public License v3.0
~ which accompanies this distribution, and is available at
~ http://www.gnu.org/licenses/gpl.html
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:typeface="monospace"
android:id="@+id/text_report"/>
</ScrollView>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering).
~ All rights reserved. This program and the accompanying materials
~ are made available under the terms of the GNU Public License v3.0
~ which accompanies this distribution, and is available at
~ http://www.gnu.org/licenses/gpl.html
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:icon="@android:drawable/ic_menu_share"
android:title="@string/share"
android:showAsAction="always"
android:onClick="onShare" />
</menu>
\ No newline at end of file
......@@ -11,5 +11,6 @@
<item android:onClick="addAccount" android:title="@string/setup_add_account" android:showAsAction="always" android:icon="@drawable/ic_action_new_account"/>
<item android:onClick="showSyncSettings" android:title="@string/main_manage_accounts" android:showAsAction="always" android:icon="@drawable/show_sync_settings"/>
<item android:onClick="showSettings" android:title="@string/settings_title" android:showAsAction="never" android:icon="@drawable/ic_action_settings"/>
<item android:onClick="showDebugInfo" android:title="@string/main_show_debug_info" android:showAsAction="never" />
<item android:onClick="showWebsite" android:title="@string/help" android:showAsAction="ifRoom" android:icon="@drawable/view_website"/>
</menu>
......@@ -177,6 +177,18 @@
<string name="setup_account_name_info">&quot;Verwenden Sie Ihre Email-Adresse als Kontoname, da Android den Kontonamen als ORGANIZER-Feld in Terminen benutzt. Sie können keine zwei Konten mit dem gleichen Namen anlegen.</string>
<string name="setup_read_only">schreibgeschützt</string>
<string name="sync_error_title">Synchronisierung fehlgeschlagen</string>
<string name="sync_error_title">Synchronisierung von %s fehlgeschlagen</string>
<string name="sync_error_http">HTTP-Fehler beim %1$s</string>
<string-array name="sync_error_phases">
<item>Abfragen der Server-Fähigkeiten</item>
<item>Verarbeiten lokal gelöschter Einträge</item>
<item>Vorbereiten neuer lokaler Einträge</item>
<item>Hochladen neuer/geänderter lokaler Einträge</item>
<item>Abfragen des Sync.-Zustands</item>
<item>Auflisten lokaler Einträge</item>
<item>Auflisten der Server-Einträge</item>
<item>Herunterladen von Server-Einträgen</item>
<item>Speichern des Sync.-Zustands</item>
</string-array>
</resources>
\ No newline at end of file
......@@ -11,9 +11,10 @@
<!-- common strings -->
<string name="app_name">DAVdroid</string>
<string name="help">Help</string>
<string name="next">Next</string>
<string name="share">Share</string>
<string name="skip">Skip</string>
<string name="help">Help</string>
<string name="exception_cert_path_validation">Untrusted certificate in certificate path. See FAQ for more info.</string>
<string name="exception_http">HTTP error: %s</string>
......@@ -23,6 +24,7 @@
<!-- MainActivity -->
<string name="main_manage_accounts">Manage sync accounts</string>
<string name="main_show_debug_info">Show debug info</string>
<string name="html_main_workaround"><![CDATA[
<p>Thank you for buying DAVdroid via Google Play and thus supporting the project. Unfortunately, there are two issues with Google Play:</p>
......@@ -188,6 +190,20 @@
<string name="setup_account_name_info">"Use your email address as account name because Android will use the account name as ORGANIZER field for events you create. You can't have two accounts with the same name.</string>
<string name="setup_read_only">read-only</string>
<string name="sync_error_title">Synchronization failed</string>
<!-- sync errors and DebugInfoActivity -->
<string name="debug_info_title">Debug info</string>
<string name="sync_error_title">Synchronization of %s failed</string>
<string name="sync_error_http">HTTP error while %1$s</string>
<string-array name="sync_error_phases">
<item>querying capabilities</item>
<item>processing locally deleted entries</item>
<item>preparing locally created entries</item>
<item>uploading created/modified entries</item>
<item>checking sync state</item>
<item>listing local entries</item>
<item>listing remote entries</item>
<item>downloading remote entries</item>
<item>saving sync state</item>
</string-array>
</resources>
Subproject commit 8258787df4c29697e76c683d1b9e4caea42205ec
Subproject commit e6c3ee6da90a94d3c77675b8fdd9be7e2d5f83e3
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment