Commit c6aed90c authored by Ricki Hirner's avatar Ricki Hirner

OOM handling, DB transactions, calandar VISIBLE, service refresh notification

* handle and show OutOfMemoryErrors correctly (they're not Exceptions)
* use db.beginTransactionNonExclusive() because WAL is enabled
* set calendar VISIBLE=1 AND SYNC=1 only at creation and not at every sync
* update PendingIntent of service refresh notification
parent 2280f899
......@@ -22,6 +22,8 @@ import android.database.sqlite.SQLiteDatabase;
import android.graphics.drawable.BitmapDrawable;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.NotificationCompat;
import android.text.TextUtils;
......@@ -274,7 +276,7 @@ public class DavService extends Service {
}
try {
db.beginTransaction();
db.beginTransactionNonExclusive();
saveHomeSets(homeSets);
saveCollections(collections.values());
db.setTransactionSuccessful();
......@@ -288,7 +290,7 @@ public class DavService extends Service {
App.log.log(Level.SEVERE, "Couldn't refresh collection list", e);
Intent debugIntent = new Intent(DavService.this, DebugInfoActivity.class);
debugIntent.putExtra(DebugInfoActivity.KEY_EXCEPTION, e);
debugIntent.putExtra(DebugInfoActivity.KEY_THROWABLE, e);
if (account != null)
debugIntent.putExtra(DebugInfoActivity.KEY_ACCOUNT, account);
......@@ -298,7 +300,7 @@ public class DavService extends Service {
.setLargeIcon(((BitmapDrawable)getResources().getDrawable(R.drawable.ic_launcher)).getBitmap())
.setContentTitle(getString(R.string.dav_service_refresh_failed))
.setContentText(getString(R.string.dav_service_refresh_couldnt_refresh))
.setContentIntent(PendingIntent.getActivity(DavService.this, 0, debugIntent, 0))
.setContentIntent(PendingIntent.getActivity(DavService.this, 0, debugIntent, PendingIntent.FLAG_UPDATE_CURRENT))
.build();
nm.notify(Constants.NOTIFICATION_REFRESH_COLLECTIONS, notify);
} finally {
......@@ -333,6 +335,7 @@ public class DavService extends Service {
}
@NonNull
private Account account() {
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[] { Services.ACCOUNT_NAME }, Services.ID + "=?", new String[] { String.valueOf(service) }, null, null, null);
if (cursor.moveToNext()) {
......@@ -341,6 +344,7 @@ public class DavService extends Service {
throw new IllegalArgumentException("Service not found");
}
@NonNull
private String serviceType() {
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[] { Services.SERVICE }, Services.ID + "=?", new String[] { String.valueOf(service) }, null, null, null);
if (cursor.moveToNext())
......@@ -349,6 +353,7 @@ public class DavService extends Service {
throw new IllegalArgumentException("Service not found");
}
@Nullable
private HttpUrl readPrincipal() {
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[] { Services.PRINCIPAL }, Services.ID + "=?", new String[] { String.valueOf(service) }, null, null, null);
if (cursor.moveToNext()) {
......@@ -359,6 +364,7 @@ public class DavService extends Service {
return null;
}
@NonNull
private Set<HttpUrl> readHomeSets() {
Set<HttpUrl> homeSets = new LinkedHashSet<>();
@Cleanup Cursor cursor = db.query(HomeSets._TABLE, new String[] { HomeSets.URL }, HomeSets.SERVICE_ID + "=?", new String[] { String.valueOf(service) }, null, null, null);
......@@ -377,6 +383,7 @@ public class DavService extends Service {
}
}
@NonNull
private Map<HttpUrl, CollectionInfo> readCollections() {
Map<HttpUrl, CollectionInfo> collections = new LinkedHashMap<>();
@Cleanup Cursor cursor = db.query(Collections._TABLE, null, Collections.SERVICE_ID + "=?", new String[]{String.valueOf(service)}, null, null, null);
......
......@@ -80,6 +80,10 @@ public class LocalCalendar extends AndroidCalendar implements LocalCollection {
values.put(Calendars.ACCOUNT_TYPE, account.type);
values.put(Calendars.OWNER_ACCOUNT, account.name);
// flag as visible & synchronizable at creation, might be changed by user at any time
values.put(Calendars.VISIBLE, 1);
values.put(Calendars.SYNC_EVENTS, 1);
return create(account, provider, values);
}
......@@ -102,8 +106,6 @@ public class LocalCalendar extends AndroidCalendar implements LocalCollection {
values.put(Calendars.CAN_ORGANIZER_RESPOND, 1);
}
values.put(Calendars.SYNC_EVENTS, 1);
values.put(Calendars.VISIBLE, 1);
if (!TextUtils.isEmpty(info.timeZone)) {
VTimeZone timeZone = DateUtils.parseVTimeZone(info.timeZone);
if (timeZone != null && timeZone.getTimeZoneId() != null)
......
......@@ -9,14 +9,12 @@ package at.bitfire.davdroid.syncadapter;
import android.accounts.Account;
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SyncResult;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.NotificationCompat;
import android.text.TextUtils;
......@@ -46,7 +44,6 @@ import at.bitfire.davdroid.InvalidAccountException;
import at.bitfire.davdroid.R;
import at.bitfire.davdroid.resource.LocalCollection;
import at.bitfire.davdroid.resource.LocalResource;
import at.bitfire.davdroid.ui.AccountActivity;
import at.bitfire.davdroid.ui.AccountSettingsActivity;
import at.bitfire.davdroid.ui.DebugInfoActivity;
import at.bitfire.ical4android.CalendarStorageException;
......@@ -215,7 +212,7 @@ abstract public class SyncManager {
detailsIntent.putExtra(AccountSettingsActivity.EXTRA_ACCOUNT, account);
} else {
detailsIntent = new Intent(context, DebugInfoActivity.class);
detailsIntent.putExtra(DebugInfoActivity.KEY_EXCEPTION, e);
detailsIntent.putExtra(DebugInfoActivity.KEY_THROWABLE, e);
detailsIntent.putExtra(DebugInfoActivity.KEY_ACCOUNT, account);
detailsIntent.putExtra(DebugInfoActivity.KEY_AUTHORITY, authority);
detailsIntent.putExtra(DebugInfoActivity.KEY_PHASE, syncPhase);
......
......@@ -197,7 +197,7 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
OpenHelper dbHelper = new OpenHelper(AccountActivity.this);
try {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.beginTransaction();
db.beginTransactionNonExclusive();
if (list.getChoiceMode() == AbsListView.CHOICE_MODE_SINGLE) {
// disable all other collections
......
......@@ -17,19 +17,13 @@ import android.content.Context;
import android.content.Intent;
import android.content.Loader;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
import android.support.v4.database.DatabaseUtilsCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
......@@ -55,7 +49,7 @@ import lombok.Cleanup;
public class DebugInfoActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<String> {
public static final String
KEY_EXCEPTION = "exception",
KEY_THROWABLE = "throwable",
KEY_LOGS = "logs",
KEY_ACCOUNT = "account",
KEY_AUTHORITY = "authority",
......@@ -151,14 +145,14 @@ public class DebugInfoActivity extends AppCompatActivity implements LoaderManage
@Override
public String loadInBackground() {
Exception exception = null;
Throwable throwable = null;
String logs = null,
authority = null;
Account account = null;
int phase = -1;
if (extras != null) {
exception = (Exception)extras.getSerializable(KEY_EXCEPTION);
throwable = (Throwable)extras.getSerializable(KEY_THROWABLE);
logs = extras.getString(KEY_LOGS);
account = extras.getParcelable(KEY_ACCOUNT);
authority = extras.getString(KEY_AUTHORITY);
......@@ -176,17 +170,17 @@ public class DebugInfoActivity extends AppCompatActivity implements LoaderManage
if (authority != null)
report.append("Authority: ").append(authority).append("\n");
if (exception instanceof HttpException) {
HttpException http = (HttpException)exception;
if (throwable instanceof HttpException) {
HttpException http = (HttpException)throwable;
if (http.request != null)
report.append("\nHTTP REQUEST:\n").append(http.request).append("\n\n");
if (http.response != null)
report.append("HTTP RESPONSE:\n").append(http.response).append("\n");
}
if (exception != null)
if (throwable != null)
report .append("\nEXCEPTION:\n")
.append(ExceptionUtils.getStackTrace(exception));
.append(ExceptionUtils.getStackTrace(throwable));
if (logs != null)
report.append("\nLOGS:\n").append(logs).append("\n");
......
......@@ -57,7 +57,7 @@ public class ExceptionInfoFragment extends DialogFragment {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(getContext(), DebugInfoActivity.class);
intent.putExtra(DebugInfoActivity.KEY_EXCEPTION, exception);
intent.putExtra(DebugInfoActivity.KEY_THROWABLE, exception);
if (account != null)
intent.putExtra(DebugInfoActivity.KEY_ACCOUNT, account);
startActivity(intent);
......
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