mirror of
https://github.com/etesync/android
synced 2025-05-22 08:48:49 +00:00
Show debug info on management errors
This commit is contained in:
parent
19bfe5c5f2
commit
6ac5fe0204
@ -10,11 +10,13 @@ package at.bitfire.davdroid.ui;
|
|||||||
|
|
||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
|
import android.support.v4.app.NavUtils;
|
||||||
import android.support.v4.content.AsyncTaskLoader;
|
import android.support.v4.content.AsyncTaskLoader;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
@ -96,6 +98,17 @@ public class CreateCalendarActivity extends AppCompatActivity implements LoaderM
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
if (item.getItemId() == android.R.id.home) {
|
||||||
|
Intent intent = new Intent(this, AccountActivity.class);
|
||||||
|
intent.putExtra(AccountActivity.EXTRA_ACCOUNT_NAME, account.name);
|
||||||
|
NavUtils.navigateUpTo(this, intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public void onCreateCalendar(MenuItem item) {
|
public void onCreateCalendar(MenuItem item) {
|
||||||
boolean ok = true;
|
boolean ok = true;
|
||||||
CollectionInfo info = new CollectionInfo();
|
CollectionInfo info = new CollectionInfo();
|
||||||
|
@ -13,14 +13,16 @@ import android.app.Activity;
|
|||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.design.widget.Snackbar;
|
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
import android.widget.Toast;
|
import android.support.v4.app.LoaderManager;
|
||||||
|
import android.support.v4.content.AsyncTaskLoader;
|
||||||
|
import android.support.v4.content.Loader;
|
||||||
|
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.xmlpull.v1.XmlSerializer;
|
import org.xmlpull.v1.XmlSerializer;
|
||||||
@ -38,16 +40,18 @@ import at.bitfire.davdroid.R;
|
|||||||
import at.bitfire.davdroid.model.CollectionInfo;
|
import at.bitfire.davdroid.model.CollectionInfo;
|
||||||
import at.bitfire.davdroid.model.ServiceDB;
|
import at.bitfire.davdroid.model.ServiceDB;
|
||||||
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
||||||
import at.bitfire.ical4android.DateUtils;
|
|
||||||
import lombok.Cleanup;
|
import lombok.Cleanup;
|
||||||
import okhttp3.HttpUrl;
|
import okhttp3.HttpUrl;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
|
|
||||||
public class CreateCollectionFragment extends DialogFragment {
|
public class CreateCollectionFragment extends DialogFragment implements LoaderManager.LoaderCallbacks<Exception> {
|
||||||
private static final String
|
private static final String
|
||||||
ARG_ACCOUNT = "account",
|
ARG_ACCOUNT = "account",
|
||||||
ARG_COLLECTION_INFO = "collectionInfo";
|
ARG_COLLECTION_INFO = "collectionInfo";
|
||||||
|
|
||||||
|
protected Account account;
|
||||||
|
protected CollectionInfo info;
|
||||||
|
|
||||||
public static CreateCollectionFragment newInstance(Account account, CollectionInfo info) {
|
public static CreateCollectionFragment newInstance(Account account, CollectionInfo info) {
|
||||||
CreateCollectionFragment frag = new CreateCollectionFragment();
|
CreateCollectionFragment frag = new CreateCollectionFragment();
|
||||||
Bundle args = new Bundle(2);
|
Bundle args = new Bundle(2);
|
||||||
@ -60,9 +64,11 @@ public class CreateCollectionFragment extends DialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setRetainInstance(true);
|
|
||||||
|
|
||||||
new CreateCollectionTask().execute(getArguments());
|
account = getArguments().getParcelable(ARG_ACCOUNT);
|
||||||
|
info = (CollectionInfo)getArguments().getSerializable(ARG_COLLECTION_INFO);
|
||||||
|
|
||||||
|
getLoaderManager().initLoader(0, null, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -77,12 +83,50 @@ public class CreateCollectionFragment extends DialogFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected class CreateCollectionTask extends AsyncTask<Bundle, Void, Exception> {
|
@Override
|
||||||
|
public Loader<Exception> onCreateLoader(int id, Bundle args) {
|
||||||
|
return new CreateCollectionLoader(getContext(), account, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadFinished(Loader<Exception> loader, Exception exception) {
|
||||||
|
dismissAllowingStateLoss();
|
||||||
|
|
||||||
|
Activity parent = getActivity();
|
||||||
|
if (parent != null) {
|
||||||
|
if (exception != null)
|
||||||
|
getFragmentManager().beginTransaction()
|
||||||
|
.add(ExceptionInfoFragment.newInstance(exception, account), null)
|
||||||
|
.commitAllowingStateLoss();
|
||||||
|
else
|
||||||
|
parent.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoaderReset(Loader<Exception> loader) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected static class CreateCollectionLoader extends AsyncTaskLoader<Exception> {
|
||||||
|
final Account account;
|
||||||
|
final CollectionInfo info;
|
||||||
|
|
||||||
|
public CreateCollectionLoader(Context context, Account account, CollectionInfo info) {
|
||||||
|
super(context);
|
||||||
|
this.account = account;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Exception doInBackground(Bundle... params) {
|
protected void onStartLoading() {
|
||||||
Bundle args = params[0];
|
forceLoad();
|
||||||
Account account = args.getParcelable(ARG_ACCOUNT);
|
}
|
||||||
CollectionInfo info = (CollectionInfo)args.getSerializable(ARG_COLLECTION_INFO);
|
|
||||||
|
@Override
|
||||||
|
public Exception loadInBackground() {
|
||||||
|
Constants.log.info("MKCOl !!!!");
|
||||||
|
|
||||||
OkHttpClient client = HttpClient.create(getContext());
|
OkHttpClient client = HttpClient.create(getContext());
|
||||||
client = HttpClient.addAuthentication(client, new AccountSettings(getContext(), account));
|
client = HttpClient.addAuthentication(client, new AccountSettings(getContext(), account));
|
||||||
@ -204,19 +248,6 @@ public class CreateCollectionFragment extends DialogFragment {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Exception e) {
|
|
||||||
dismissAllowingStateLoss();
|
|
||||||
|
|
||||||
Activity parent = getActivity();
|
|
||||||
if (parent != null) {
|
|
||||||
if (e != null)
|
|
||||||
Toast.makeText(parent, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
|
|
||||||
else
|
|
||||||
parent.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -161,25 +161,25 @@ public class DebugInfoActivity extends AppCompatActivity implements LoaderManage
|
|||||||
if (account != null)
|
if (account != null)
|
||||||
report.append("Account name: " + account.name + "\n");
|
report.append("Account name: " + account.name + "\n");
|
||||||
if (authority != null)
|
if (authority != null)
|
||||||
report.append("Authority: " + authority + "\n\n");
|
report.append("Authority: " + authority + "\n");
|
||||||
|
|
||||||
if (exception instanceof HttpException) {
|
if (exception instanceof HttpException) {
|
||||||
HttpException http = (HttpException)exception;
|
HttpException http = (HttpException)exception;
|
||||||
if (http.request != null)
|
if (http.request != null)
|
||||||
report.append("HTTP REQUEST:\n" + http.request + "\n\n");
|
report.append("\nHTTP REQUEST:\n" + http.request + "\n\n");
|
||||||
if (http.response != null)
|
if (http.response != null)
|
||||||
report.append("HTTP RESPONSE:\n" + http.response + "\n\n");
|
report.append("HTTP RESPONSE:\n" + http.response + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exception != null) {
|
if (exception != null) {
|
||||||
report.append("STACK TRACE:\n");
|
report.append("\nSTACK TRACE:\n");
|
||||||
for (String stackTrace : ExceptionUtils.getRootCauseStackTrace(exception))
|
for (String stackTrace : ExceptionUtils.getRootCauseStackTrace(exception))
|
||||||
report.append(stackTrace + "\n");
|
report.append(stackTrace + "\n");
|
||||||
report.append("\n");
|
report.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logs != null)
|
if (logs != null)
|
||||||
report.append("LOGS:\n" + logs + "\n");
|
report.append("\nLOGS:\n" + logs + "\n");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PackageManager pm = getContext().getPackageManager();
|
PackageManager pm = getContext().getPackageManager();
|
||||||
@ -191,7 +191,7 @@ public class DebugInfoActivity extends AppCompatActivity implements LoaderManage
|
|||||||
workaroundInstalled = pm.getPackageInfo("at.bitfire.davdroid.jbworkaround", 0) != null;
|
workaroundInstalled = pm.getPackageInfo("at.bitfire.davdroid.jbworkaround", 0) != null;
|
||||||
} catch(PackageManager.NameNotFoundException e) {}
|
} catch(PackageManager.NameNotFoundException e) {}
|
||||||
report.append(
|
report.append(
|
||||||
"SOFTWARE INFORMATION\n" +
|
"\nSOFTWARE INFORMATION\n" +
|
||||||
"DAVdroid version: " + BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ") " + new Date(BuildConfig.buildTime) + "\n" +
|
"DAVdroid version: " + BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ") " + new Date(BuildConfig.buildTime) + "\n" +
|
||||||
"Installed from: " + installedFrom + "\n" +
|
"Installed from: " + installedFrom + "\n" +
|
||||||
"JB Workaround installed: " + (workaroundInstalled ? "yes" : "no") + "\n\n"
|
"JB Workaround installed: " + (workaroundInstalled ? "yes" : "no") + "\n\n"
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
package at.bitfire.davdroid.ui;
|
package at.bitfire.davdroid.ui;
|
||||||
|
|
||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -22,7 +23,6 @@ import android.support.v4.content.AsyncTaskLoader;
|
|||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@ -41,9 +41,13 @@ public class DeleteCollectionFragment extends DialogFragment implements LoaderMa
|
|||||||
ARG_ACCOUNT = "account",
|
ARG_ACCOUNT = "account",
|
||||||
ARG_COLLECTION_INFO = "collectionInfo";
|
ARG_COLLECTION_INFO = "collectionInfo";
|
||||||
|
|
||||||
|
protected Account account;
|
||||||
|
protected CollectionInfo collectionInfo;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
getLoaderManager().initLoader(0, getArguments(), this);
|
getLoaderManager().initLoader(0, getArguments(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,42 +65,41 @@ public class DeleteCollectionFragment extends DialogFragment implements LoaderMa
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Loader<Exception> onCreateLoader(int id, Bundle args) {
|
public Loader<Exception> onCreateLoader(int id, Bundle args) {
|
||||||
CollectionInfo collectionInfo = (CollectionInfo)args.getSerializable(ARG_COLLECTION_INFO);
|
account = args.getParcelable(ARG_ACCOUNT);
|
||||||
return new DeleteCollectionLoader(
|
collectionInfo = (CollectionInfo)args.getSerializable(ARG_COLLECTION_INFO);
|
||||||
getContext(),
|
return new DeleteCollectionLoader(getContext(), account, collectionInfo);
|
||||||
(Account)args.getParcelable(ARG_ACCOUNT),
|
|
||||||
collectionInfo.id,
|
|
||||||
HttpUrl.parse(collectionInfo.url)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadFinished(Loader<Exception> loader, Exception exception) {
|
public void onLoadFinished(Loader loader, Exception exception) {
|
||||||
if (exception != null)
|
|
||||||
Toast.makeText(getContext(), exception.getLocalizedMessage(), Toast.LENGTH_LONG).show();
|
|
||||||
dismissAllowingStateLoss();
|
dismissAllowingStateLoss();
|
||||||
|
|
||||||
AccountActivity activity = (AccountActivity)getActivity();
|
if (exception != null)
|
||||||
activity.reload();
|
getFragmentManager().beginTransaction()
|
||||||
|
.add(ExceptionInfoFragment.newInstance(exception, account), null)
|
||||||
|
.commitAllowingStateLoss();
|
||||||
|
else {
|
||||||
|
Activity activity = getActivity();
|
||||||
|
if (activity instanceof AccountActivity)
|
||||||
|
((AccountActivity)activity).reload();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoaderReset(Loader<Exception> loader) {
|
public void onLoaderReset(Loader loader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class DeleteCollectionLoader extends AsyncTaskLoader<Exception> {
|
|
||||||
|
protected static class DeleteCollectionLoader extends AsyncTaskLoader<Exception> {
|
||||||
final Account account;
|
final Account account;
|
||||||
final long collectionId;
|
final CollectionInfo collectionInfo;
|
||||||
final HttpUrl url;
|
|
||||||
final ServiceDB.OpenHelper dbHelper;
|
final ServiceDB.OpenHelper dbHelper;
|
||||||
|
|
||||||
public DeleteCollectionLoader(Context context, Account account, long collectionId, HttpUrl url) {
|
public DeleteCollectionLoader(Context context, Account account, CollectionInfo collectionInfo) {
|
||||||
super(context);
|
super(context);
|
||||||
this.account = account;
|
this.account = account;
|
||||||
this.collectionId = collectionId;
|
this.collectionInfo = collectionInfo;
|
||||||
this.url = url;
|
dbHelper = new ServiceDB.OpenHelper(getContext());
|
||||||
|
|
||||||
dbHelper = new ServiceDB.OpenHelper(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -109,14 +112,14 @@ public class DeleteCollectionFragment extends DialogFragment implements LoaderMa
|
|||||||
OkHttpClient httpClient = HttpClient.create(getContext());
|
OkHttpClient httpClient = HttpClient.create(getContext());
|
||||||
httpClient = HttpClient.addAuthentication(httpClient, new AccountSettings(getContext(), account));
|
httpClient = HttpClient.addAuthentication(httpClient, new AccountSettings(getContext(), account));
|
||||||
|
|
||||||
DavResource collection = new DavResource(null, httpClient, url);
|
DavResource collection = new DavResource(null, httpClient, HttpUrl.parse(collectionInfo.url));
|
||||||
try {
|
try {
|
||||||
// delete collection from server
|
// delete collection from server
|
||||||
collection.delete(null);
|
collection.delete(null);
|
||||||
|
|
||||||
// delete collection locally
|
// delete collection locally
|
||||||
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
||||||
db.delete(ServiceDB.Collections._TABLE, ServiceDB.Collections.ID + "=?", new String[] { String.valueOf(collectionId) });
|
db.delete(ServiceDB.Collections._TABLE, ServiceDB.Collections.ID + "=?", new String[] { String.valueOf(collectionInfo.id) });
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
} catch (IOException|HttpException e) {
|
} catch (IOException|HttpException e) {
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2013 – 2016 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.Dialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.support.v7.app.AlertDialog;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import at.bitfire.dav4android.exception.HttpException;
|
||||||
|
import at.bitfire.davdroid.R;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
public class ExceptionInfoFragment extends DialogFragment {
|
||||||
|
protected static final String
|
||||||
|
ARG_ACCOUNT = "account",
|
||||||
|
ARG_EXCEPTION = "exception";
|
||||||
|
|
||||||
|
public static ExceptionInfoFragment newInstance(@NonNull Exception exception, Account account) {
|
||||||
|
ExceptionInfoFragment frag = new ExceptionInfoFragment();
|
||||||
|
Bundle args = new Bundle(1);
|
||||||
|
args.putSerializable(ARG_EXCEPTION, exception);
|
||||||
|
args.putParcelable(ARG_ACCOUNT, account);
|
||||||
|
frag.setArguments(args);
|
||||||
|
return frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
Bundle args = getArguments();
|
||||||
|
final Exception exception = (Exception)args.getSerializable(ARG_EXCEPTION);
|
||||||
|
final Account account = args.getParcelable(ARG_ACCOUNT);
|
||||||
|
|
||||||
|
int title = R.string.exception;
|
||||||
|
if (exception instanceof HttpException)
|
||||||
|
title = R.string.exception_httpexception;
|
||||||
|
else if (exception instanceof IOException)
|
||||||
|
title = R.string.exception_ioexception;
|
||||||
|
|
||||||
|
Dialog dialog = new AlertDialog.Builder(getContext())
|
||||||
|
.setIcon(R.drawable.ic_error_dark)
|
||||||
|
.setTitle(title)
|
||||||
|
.setMessage(exception.getClass().getCanonicalName() + "\n" + exception.getLocalizedMessage())
|
||||||
|
.setPositiveButton(R.string.exception_show_details, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
Intent intent = new Intent(getContext(), DebugInfoActivity.class);
|
||||||
|
intent.putExtra(DebugInfoActivity.KEY_EXCEPTION, exception);
|
||||||
|
if (account != null)
|
||||||
|
intent.putExtra(DebugInfoActivity.KEY_ACCOUNT, account);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create();
|
||||||
|
setCancelable(false);
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
}
|
@ -179,6 +179,12 @@
|
|||||||
<string name="delete_collection_confirm_warning">This collection (%s) and all its entries from the server will be removed from the server.</string>
|
<string name="delete_collection_confirm_warning">This collection (%s) and all its entries from the server will be removed from the server.</string>
|
||||||
<string name="delete_collection_deleting_collection">Deleting collection</string>
|
<string name="delete_collection_deleting_collection">Deleting collection</string>
|
||||||
|
|
||||||
|
<!-- ExceptionInfoFragment -->
|
||||||
|
<string name="exception">An error has occurred.</string>
|
||||||
|
<string name="exception_httpexception">An HTTP error has occurred.</string>
|
||||||
|
<string name="exception_ioexception">An I/O error has occurred.</string>
|
||||||
|
<string name="exception_show_details">Show details</string>
|
||||||
|
|
||||||
<string name="settings_android_update_title">Android version update</string>
|
<string name="settings_android_update_title">Android version update</string>
|
||||||
<string name="settings_android_update_description">Android version updates may have an impact on how DAVdroid works. If there are problems, please delete your DAVdroid accounts and add them again.</string>
|
<string name="settings_android_update_description">Android version updates may have an impact on how DAVdroid works. If there are problems, please delete your DAVdroid accounts and add them again.</string>
|
||||||
<string name="settings_version_update_title">Settings have been updated</string>
|
<string name="settings_version_update_title">Settings have been updated</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user