From c6aed90c9608ec6eb4ce81e9a2111cc1ef608360 Mon Sep 17 00:00:00 2001 From: Ricki Hirner Date: Thu, 31 Mar 2016 12:21:58 +0200 Subject: [PATCH] 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 --- .../java/at/bitfire/davdroid/DavService.java | 13 +++++++++--- .../davdroid/resource/LocalCalendar.java | 6 ++++-- .../davdroid/syncadapter/SyncManager.java | 5 +---- .../bitfire/davdroid/ui/AccountActivity.java | 2 +- .../davdroid/ui/DebugInfoActivity.java | 20 +++++++------------ .../davdroid/ui/ExceptionInfoFragment.java | 2 +- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/at/bitfire/davdroid/DavService.java b/app/src/main/java/at/bitfire/davdroid/DavService.java index 8b1eaee9..0d3bfc50 100644 --- a/app/src/main/java/at/bitfire/davdroid/DavService.java +++ b/app/src/main/java/at/bitfire/davdroid/DavService.java @@ -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 readHomeSets() { Set 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 readCollections() { Map collections = new LinkedHashMap<>(); @Cleanup Cursor cursor = db.query(Collections._TABLE, null, Collections.SERVICE_ID + "=?", new String[]{String.valueOf(service)}, null, null, null); diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java b/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java index 752c46d3..eca6f597 100644 --- a/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java +++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java @@ -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) diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.java b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.java index 9a3cc241..1f6e2951 100644 --- a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.java +++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.java @@ -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); diff --git a/app/src/main/java/at/bitfire/davdroid/ui/AccountActivity.java b/app/src/main/java/at/bitfire/davdroid/ui/AccountActivity.java index 53e4b1b3..84b01ac4 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/AccountActivity.java +++ b/app/src/main/java/at/bitfire/davdroid/ui/AccountActivity.java @@ -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 diff --git a/app/src/main/java/at/bitfire/davdroid/ui/DebugInfoActivity.java b/app/src/main/java/at/bitfire/davdroid/ui/DebugInfoActivity.java index 2f71bb4b..415544a5 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/DebugInfoActivity.java +++ b/app/src/main/java/at/bitfire/davdroid/ui/DebugInfoActivity.java @@ -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 { 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"); diff --git a/app/src/main/java/at/bitfire/davdroid/ui/ExceptionInfoFragment.java b/app/src/main/java/at/bitfire/davdroid/ui/ExceptionInfoFragment.java index 02993709..b39400f3 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/ExceptionInfoFragment.java +++ b/app/src/main/java/at/bitfire/davdroid/ui/ExceptionInfoFragment.java @@ -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);