Compare commits

..

7 Commits
v1.2 ... v1.2.2

Author SHA1 Message Date
Ricki Hirner
ae145d897e Fetch translations from Transifex 2016-08-02 19:30:20 +02:00
Ricki Hirner
d675fb961e Request ignoring battery optimization
* startup dialog: request to ignore battery optimizations
* remove F-Droid donation startup dialog (only useful for davdroid-ose)
* version bump to 1.2.2
2016-08-02 19:30:15 +02:00
Ricki Hirner
967bc50256 Avoid sync error when OpenTasks is not installed 2016-08-01 21:54:56 +02:00
Ricki Hirner
2617063835 Clean up launcher icon
* clean up launcher icon
* update dependencies
2016-08-01 21:15:55 +02:00
Ricki Hirner
7fbdf96546 Allow large transactions
* version bump to 1.2.1-ose
* upgrade to okhttp 3.4.1
* ical4android/vcard4android: split oversized transactions
2016-07-27 14:33:06 +02:00
Ricki Hirner
f6cb92dd6d Remove gplay flavour to keep DAVdroid-OSE repo clean
* Remove gplay flavour to keep DAVdroid-OSE repo clean
* update Android gradle plugin to 2.1.2
2016-07-11 13:45:27 +02:00
Ricki Hirner
b49bdda7e8 Fix NPE, add intent to view FAQ to upgrade notification 2016-07-11 12:55:55 +02:00
26 changed files with 231 additions and 227 deletions

6
.gitmodules vendored
View File

@@ -1,12 +1,12 @@
[submodule "dav4android"]
path = dav4android
url = https://gitlab.com/bitfireAT/dav4android.git
url = ../dav4android.git
[submodule "ical4android"]
path = ical4android
url = https://gitlab.com/bitfireAT/ical4android.git
url = ../ical4android.git
[submodule "vcard4android"]
path = vcard4android
url = https://gitlab.com/bitfireAT/vcard4android.git
url = ../vcard4android.git
[submodule "MemorizingTrustManager"]
path = MemorizingTrustManager
url = https://github.com/ge0rg/MemorizingTrustManager

View File

@@ -9,25 +9,23 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
compileSdkVersion 24
buildToolsVersion "24.0.1"
defaultConfig {
applicationId "at.bitfire.davdroid"
minSdkVersion 14
targetSdkVersion 23
targetSdkVersion 24
versionCode 109
versionCode 111
buildConfigField "long", "buildTime", System.currentTimeMillis() + "L"
buildConfigField "boolean", "useMTM", "true"
}
productFlavors {
standard {
versionName "1.2"
}
gplay {
versionName "1.2-gplay"
versionName "1.2.2-ose"
}
}
@@ -68,10 +66,10 @@ dependencies {
compile project(':ical4android')
compile project(':vcard4android')
compile 'com.android.support:appcompat-v7:23.+'
compile 'com.android.support:cardview-v7:23.+'
compile 'com.android.support:design:23.+'
compile 'com.android.support:preference-v14:23.+'
compile 'com.android.support:appcompat-v7:24.+'
compile 'com.android.support:cardview-v7:24.+'
compile 'com.android.support:design:24.+'
compile 'com.android.support:preference-v14:24.+'
compile 'com.github.yukuku:ambilwarna:2.0.1'
compile project(':MemorizingTrustManager')
@@ -79,10 +77,10 @@ dependencies {
compile 'dnsjava:dnsjava:2.1.7'
compile 'org.apache.commons:commons-lang3:3.4'
compile 'org.apache.commons:commons-collections4:4.1'
provided 'org.projectlombok:lombok:1.16.8'
provided 'org.projectlombok:lombok:1.16.10'
// for tests
testCompile 'junit:junit:4.12'
testCompile 'com.squareup.okhttp3:mockwebserver:3.3.1'
androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.3.1'
testCompile 'com.squareup.okhttp3:mockwebserver:3.4.1'
androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.4.1'
}

View File

@@ -1,55 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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
-->
<menu xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/nav_about"
android:icon="@drawable/ic_info_dark"
android:title="@string/navigation_drawer_about"/>
<item
android:id="@+id/nav_app_settings"
android:icon="@drawable/ic_settings_dark"
android:title="@string/navigation_drawer_settings"/>
<item android:title="@string/navigation_drawer_news_updates">
<menu>
<item
android:id="@+id/nav_twitter"
android:icon="@drawable/twitter"
android:title="\@davdroidapp"
tools:ignore="HardcodedText"/>
</menu>
</item>
<item android:title="@string/navigation_drawer_external_links">
<menu>
<item
android:id="@+id/nav_website"
android:icon="@drawable/ic_home_dark"
android:title="@string/navigation_drawer_website"/>
<item
android:id="@+id/nav_faq"
android:icon="@drawable/ic_help_dark"
android:title="@string/navigation_drawer_faq"/>
<item
android:id="@+id/nav_forums"
android:icon="@drawable/ic_forum_dark"
android:title="@string/navigation_drawer_forums"/>
<item
android:id="@+id/nav_donate"
android:icon="@drawable/ic_attach_money_dark"
android:title="(entry disabled)"
android:visible="false"
tools:ignore="HardcodedText"/>
</menu>
</item>
</menu>

View File

@@ -19,6 +19,7 @@
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<!-- legacy permissions -->
<uses-permission

View File

@@ -10,8 +10,10 @@ package at.bitfire.davdroid;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -20,7 +22,10 @@ import android.content.Context;
import android.content.Intent;
import android.content.PeriodicSync;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
@@ -92,6 +97,7 @@ public class AccountSettings {
final Account account;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public AccountSettings(@NonNull Context context, @NonNull Account account) throws InvalidAccountException {
this.context = context;
this.account = account;
@@ -111,9 +117,16 @@ public class AccountSettings {
App.log.info("Account " + account.name + " has version " + version + ", current version: " + CURRENT_VERSION);
if (version < CURRENT_VERSION) {
Bitmap bitmapLogo = null;
Drawable drawableLogo = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP ?
context.getDrawable(R.drawable.ic_launcher) :
context.getResources().getDrawable(R.drawable.ic_launcher);
if (drawableLogo instanceof BitmapDrawable)
bitmapLogo = ((BitmapDrawable)drawableLogo).getBitmap();
Notification notify = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_new_releases_light)
.setLargeIcon(((BitmapDrawable)context.getResources().getDrawable(R.drawable.ic_launcher)).getBitmap())
.setLargeIcon(App.getLauncherBitmap(context))
.setContentTitle(context.getString(R.string.settings_version_update))
.setContentText(context.getString(R.string.settings_version_update_settings_updated))
.setSubText(context.getString(R.string.settings_version_update_install_hint))
@@ -121,6 +134,9 @@ public class AccountSettings {
.bigText(context.getString(R.string.settings_version_update_settings_updated)))
.setCategory(NotificationCompat.CATEGORY_SYSTEM)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(PendingIntent.getActivity(context, 0,
new Intent(Intent.ACTION_VIEW, Constants.webUri.buildUpon().appendEncodedPath("faq/entry/davdroid-not-working-after-update/").build()),
PendingIntent.FLAG_CANCEL_CURRENT))
.setLocalOnly(true)
.build();
NotificationManager nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);

View File

@@ -8,12 +8,18 @@
package at.bitfire.davdroid;
import android.annotation.TargetApi;
import android.app.Application;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.NotificationCompat;
import android.util.Log;
@@ -94,7 +100,7 @@ public class App extends Application {
if (logToFile) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder .setSmallIcon(R.drawable.ic_sd_storage_light)
.setLargeIcon(((BitmapDrawable)getResources().getDrawable(R.drawable.ic_launcher)).getBitmap())
.setLargeIcon(getLauncherBitmap(this))
.setContentTitle(getString(R.string.logging_davdroid_file_logging))
.setLocalOnly(true);
@@ -130,6 +136,18 @@ public class App extends Application {
nm.cancel(Constants.NOTIFICATION_EXTERNAL_FILE_LOGGING);
}
@Nullable
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static Bitmap getLauncherBitmap(@NonNull Context context) {
Bitmap bitmapLogo = null;
Drawable drawableLogo = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP ?
context.getDrawable(R.drawable.ic_launcher) :
context.getResources().getDrawable(R.drawable.ic_launcher);
if (drawableLogo instanceof BitmapDrawable)
bitmapLogo = ((BitmapDrawable)drawableLogo).getBitmap();
return bitmapLogo;
}
public static class ReinitLoggingReceiver extends BroadcastReceiver {

View File

@@ -312,7 +312,7 @@ public class DavService extends Service {
NotificationManager nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification notify = new NotificationCompat.Builder(DavService.this)
.setSmallIcon(R.drawable.ic_error_light)
.setLargeIcon(((BitmapDrawable)getResources().getDrawable(R.drawable.ic_launcher)).getBitmap())
.setLargeIcon(App.getLauncherBitmap(DavService.this))
.setContentTitle(getString(R.string.dav_service_refresh_failed))
.setContentText(getString(R.string.dav_service_refresh_couldnt_refresh))
.setContentIntent(PendingIntent.getActivity(DavService.this, 0, debugIntent, PendingIntent.FLAG_UPDATE_CURRENT))

View File

@@ -203,14 +203,15 @@ public class LocalCalendar extends AndroidCalendar implements LocalCollection {
BatchOperation batch = new BatchOperation(provider);
// re-schedule original event and set it to DIRTY
batch.enqueue(ContentProviderOperation.newUpdate(
syncAdapterURI(ContentUris.withAppendedId(Events.CONTENT_URI, originalID)))
.withValue(LocalEvent.COLUMN_SEQUENCE, originalSequence + 1)
.withValue(Events.DIRTY, DIRTY_INCREASE_SEQUENCE)
.build());
batch.enqueue(new BatchOperation.Operation(
ContentProviderOperation.newUpdate(syncAdapterURI(ContentUris.withAppendedId(Events.CONTENT_URI, originalID)))
.withValue(LocalEvent.COLUMN_SEQUENCE, originalSequence + 1)
.withValue(Events.DIRTY, DIRTY_INCREASE_SEQUENCE)
));
// remove exception
batch.enqueue(ContentProviderOperation.newDelete(
syncAdapterURI(ContentUris.withAppendedId(Events.CONTENT_URI, id))).build());
batch.enqueue(new BatchOperation.Operation(
ContentProviderOperation.newDelete(syncAdapterURI(ContentUris.withAppendedId(Events.CONTENT_URI, id)))
));
batch.commit();
}
} catch (RemoteException e) {
@@ -232,16 +233,16 @@ public class LocalCalendar extends AndroidCalendar implements LocalCollection {
BatchOperation batch = new BatchOperation(provider);
// original event to DIRTY
batch.enqueue(ContentProviderOperation.newUpdate(
syncAdapterURI(ContentUris.withAppendedId(Events.CONTENT_URI, originalID)))
.withValue(Events.DIRTY, DIRTY_DONT_INCREASE_SEQUENCE)
.build());
batch.enqueue(new BatchOperation.Operation(
ContentProviderOperation.newUpdate(syncAdapterURI(ContentUris.withAppendedId(Events.CONTENT_URI, originalID)))
.withValue(Events.DIRTY, DIRTY_DONT_INCREASE_SEQUENCE)
));
// increase SEQUENCE and set DIRTY to 0
batch.enqueue(ContentProviderOperation.newUpdate(
syncAdapterURI(ContentUris.withAppendedId(Events.CONTENT_URI, id)))
batch.enqueue(new BatchOperation.Operation(
ContentProviderOperation.newUpdate(syncAdapterURI(ContentUris.withAppendedId(Events.CONTENT_URI, id)))
.withValue(LocalEvent.COLUMN_SEQUENCE, sequence + 1)
.withValue(Events.DIRTY, 0)
.build());
));
batch.commit();
}
} catch (RemoteException e) {

View File

@@ -98,14 +98,17 @@ public class LocalContact extends AndroidContact implements LocalResource {
super.insertDataRows(batch);
if (contact.unknownProperties != null) {
ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(dataSyncURI());
if (id == null)
builder.withValueBackReference(UnknownProperties.RAW_CONTACT_ID, 0);
else
final BatchOperation.Operation op;
final ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(dataSyncURI());
if (id == null) {
op = new BatchOperation.Operation(builder, UnknownProperties.RAW_CONTACT_ID, 0);
} else {
op = new BatchOperation.Operation(builder);
builder.withValue(UnknownProperties.RAW_CONTACT_ID, id);
}
builder .withValue(UnknownProperties.MIMETYPE, UnknownProperties.CONTENT_ITEM_TYPE)
.withValue(UnknownProperties.UNKNOWN_PROPERTIES, contact.unknownProperties);
batch.enqueue(builder.build());
batch.enqueue(op);
}
}
@@ -113,35 +116,32 @@ public class LocalContact extends AndroidContact implements LocalResource {
public void addToGroup(BatchOperation batch, long groupID) {
assertID();
batch.enqueue(ContentProviderOperation
.newInsert(dataSyncURI())
.withValue(GroupMembership.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE)
.withValue(GroupMembership.RAW_CONTACT_ID, id)
.withValue(GroupMembership.GROUP_ROW_ID, groupID)
.build()
);
batch.enqueue(new BatchOperation.Operation(
ContentProviderOperation.newInsert(dataSyncURI())
.withValue(GroupMembership.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE)
.withValue(GroupMembership.RAW_CONTACT_ID, id)
.withValue(GroupMembership.GROUP_ROW_ID, groupID)
));
batch.enqueue(ContentProviderOperation
.newInsert(dataSyncURI())
.withValue(CachedGroupMembership.MIMETYPE, CachedGroupMembership.CONTENT_ITEM_TYPE)
.withValue(CachedGroupMembership.RAW_CONTACT_ID, id)
.withValue(CachedGroupMembership.GROUP_ID, groupID)
.withYieldAllowed(true)
.build()
);
batch.enqueue(new BatchOperation.Operation(
ContentProviderOperation.newInsert(dataSyncURI())
.withValue(CachedGroupMembership.MIMETYPE, CachedGroupMembership.CONTENT_ITEM_TYPE)
.withValue(CachedGroupMembership.RAW_CONTACT_ID, id)
.withValue(CachedGroupMembership.GROUP_ID, groupID)
.withYieldAllowed(true)
));
}
public void removeGroupMemberships(BatchOperation batch) {
assertID();
batch.enqueue(ContentProviderOperation
.newDelete(dataSyncURI())
.withSelection(
Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + " IN (?,?)",
new String[] { String.valueOf(id), GroupMembership.CONTENT_ITEM_TYPE, CachedGroupMembership.CONTENT_ITEM_TYPE }
)
.withYieldAllowed(true)
.build()
);
batch.enqueue(new BatchOperation.Operation(
ContentProviderOperation.newDelete(dataSyncURI())
.withSelection(
Data.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + " IN (?,?)",
new String[] { String.valueOf(id), GroupMembership.CONTENT_ITEM_TYPE, CachedGroupMembership.CONTENT_ITEM_TYPE }
)
.withYieldAllowed(true)
));
}
/**

View File

@@ -19,7 +19,6 @@ import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.RawContacts.Data;
import android.provider.ContactsContract.RawContactsEntity;
import org.apache.commons.lang3.ArrayUtils;
@@ -66,24 +65,23 @@ public class LocalGroup extends AndroidGroup implements LocalResource {
BatchOperation batch = new BatchOperation(addressBook.provider);
// delete cached group memberships
batch.enqueue(ContentProviderOperation
.newDelete(addressBook.syncAdapterURI(ContactsContract.Data.CONTENT_URI))
.withSelection(
CachedGroupMembership.MIMETYPE + "=? AND " + CachedGroupMembership.GROUP_ID + "=?",
new String[] { CachedGroupMembership.CONTENT_ITEM_TYPE, String.valueOf(id) }
).build()
);
batch.enqueue(new BatchOperation.Operation(
ContentProviderOperation.newDelete(addressBook.syncAdapterURI(ContactsContract.Data.CONTENT_URI))
.withSelection(
CachedGroupMembership.MIMETYPE + "=? AND " + CachedGroupMembership.GROUP_ID + "=?",
new String[] { CachedGroupMembership.CONTENT_ITEM_TYPE, String.valueOf(id) }
)
));
// insert updated cached group memberships
for (long member : getMembers())
batch.enqueue(ContentProviderOperation
.newInsert(addressBook.syncAdapterURI(ContactsContract.Data.CONTENT_URI))
.withValue(CachedGroupMembership.MIMETYPE, CachedGroupMembership.CONTENT_ITEM_TYPE)
.withValue(CachedGroupMembership.RAW_CONTACT_ID, member)
.withValue(CachedGroupMembership.GROUP_ID, id)
.withYieldAllowed(true)
.build()
);
batch.enqueue(new BatchOperation.Operation(
ContentProviderOperation.newInsert(addressBook.syncAdapterURI(ContactsContract.Data.CONTENT_URI))
.withValue(CachedGroupMembership.MIMETYPE, CachedGroupMembership.CONTENT_ITEM_TYPE)
.withValue(CachedGroupMembership.RAW_CONTACT_ID, member)
.withValue(CachedGroupMembership.GROUP_ID, id)
.withYieldAllowed(true)
));
batch.commit();
}
@@ -120,12 +118,11 @@ public class LocalGroup extends AndroidGroup implements LocalResource {
BatchOperation batch = new BatchOperation(addressBook.provider);
for (long member : getMembers())
batch.enqueue(ContentProviderOperation
.newUpdate(addressBook.syncAdapterURI(ContentUris.withAppendedId(RawContacts.CONTENT_URI, member)))
.withValue(RawContacts.DIRTY, 1)
.withYieldAllowed(true)
.build()
);
batch.enqueue(new BatchOperation.Operation(
ContentProviderOperation.newUpdate(addressBook.syncAdapterURI(ContentUris.withAppendedId(RawContacts.CONTENT_URI, member)))
.withValue(RawContacts.DIRTY, 1)
.withYieldAllowed(true)
));
batch.commit();
}
@@ -151,15 +148,14 @@ public class LocalGroup extends AndroidGroup implements LocalResource {
Constants.log.fine("Assigning members to group " + id);
// delete all memberships and cached memberships for this group
batch.enqueue(ContentProviderOperation
.newDelete(addressBook.syncAdapterURI(ContactsContract.Data.CONTENT_URI))
.withSelection(
"(" + GroupMembership.MIMETYPE + "=? AND " + GroupMembership.GROUP_ROW_ID + "=?) OR (" +
CachedGroupMembership.MIMETYPE + "=? AND " + CachedGroupMembership.GROUP_ID + "=?)",
new String[] { GroupMembership.CONTENT_ITEM_TYPE, String.valueOf(id), CachedGroupMembership.CONTENT_ITEM_TYPE, String.valueOf(id) })
.withYieldAllowed(true)
.build()
);
batch.enqueue(new BatchOperation.Operation(
ContentProviderOperation.newDelete(addressBook.syncAdapterURI(ContactsContract.Data.CONTENT_URI))
.withSelection(
"(" + GroupMembership.MIMETYPE + "=? AND " + GroupMembership.GROUP_ROW_ID + "=?) OR (" +
CachedGroupMembership.MIMETYPE + "=? AND " + CachedGroupMembership.GROUP_ID + "=?)",
new String[] { GroupMembership.CONTENT_ITEM_TYPE, String.valueOf(id), CachedGroupMembership.CONTENT_ITEM_TYPE, String.valueOf(id) })
.withYieldAllowed(true)
));
// extract list of member UIDs
List<String> members = new LinkedList<>();
@@ -181,12 +177,11 @@ public class LocalGroup extends AndroidGroup implements LocalResource {
}
// remove pending memberships
batch.enqueue(ContentProviderOperation
.newUpdate(addressBook.syncAdapterURI(ContentUris.withAppendedId(Groups.CONTENT_URI, id)))
.withValue(COLUMN_PENDING_MEMBERS, null)
.withYieldAllowed(true)
.build()
);
batch.enqueue(new BatchOperation.Operation(
ContentProviderOperation.newUpdate(addressBook.syncAdapterURI(ContentUris.withAppendedId(Groups.CONTENT_URI, id)))
.withValue(COLUMN_PENDING_MEMBERS, null)
.withYieldAllowed(true)
));
batch.commit();
}

View File

@@ -211,12 +211,11 @@ public class ContactsSyncManager extends SyncManager {
currentGroups = contact.getGroupMemberships();
for (Long groupID : SetUtils.disjunction(cachedGroups, currentGroups)) {
App.log.fine("Marking group as dirty: " + groupID);
batch.enqueue(ContentProviderOperation
.newUpdate(addressBook.syncAdapterURI(ContentUris.withAppendedId(Groups.CONTENT_URI, groupID)))
batch.enqueue(new BatchOperation.Operation(
ContentProviderOperation.newUpdate(addressBook.syncAdapterURI(ContentUris.withAppendedId(Groups.CONTENT_URI, groupID)))
.withValue(Groups.DIRTY, 1)
.withYieldAllowed(true)
.build()
);
));
}
} catch(FileNotFoundException ignored) {
}

View File

@@ -72,7 +72,7 @@ public abstract class SyncAdapterService extends Service {
Notification notify = new NotificationCompat.Builder(getContext())
.setSmallIcon(R.drawable.ic_error_light)
.setLargeIcon(((BitmapDrawable)getContext().getResources().getDrawable(R.drawable.ic_launcher)).getBitmap())
.setLargeIcon(App.getLauncherBitmap(getContext()))
.setContentTitle(getContext().getString(R.string.sync_error_permissions))
.setContentText(getContext().getString(R.string.sync_error_permissions_text))
.setContentIntent(PendingIntent.getActivity(getContext(), 0, intent, PendingIntent.FLAG_CANCEL_CURRENT))

View File

@@ -230,7 +230,7 @@ abstract public class SyncManager {
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder .setSmallIcon(R.drawable.ic_error_light)
.setLargeIcon(((BitmapDrawable)context.getResources().getDrawable(R.drawable.ic_launcher)).getBitmap())
.setLargeIcon(App.getLauncherBitmap(context))
.setContentTitle(getSyncErrorTitle())
.setContentIntent(PendingIntent.getActivity(context, 0, detailsIntent, PendingIntent.FLAG_CANCEL_CURRENT))
.setCategory(NotificationCompat.CATEGORY_ERROR)

View File

@@ -96,8 +96,7 @@ public class AccountsActivity extends AppCompatActivity implements NavigationVie
startActivity(new Intent(Intent.ACTION_VIEW, Constants.webUri.buildUpon().appendEncodedPath("forums/").build()));
break;
case R.id.nav_donate:
if (BuildConfig.FLAVOR != App.FLAVOR_GOOGLE_PLAY)
startActivity(new Intent(Intent.ACTION_VIEW, Constants.webUri.buildUpon().appendEncodedPath("donate/").build()));
startActivity(new Intent(Intent.ACTION_VIEW, Constants.webUri.buildUpon().appendEncodedPath("donate/").build()));
break;
}

View File

@@ -75,7 +75,7 @@ public class AppSettingsActivity extends AppCompatActivity {
private void resetHints() {
@Cleanup ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(getContext());
Settings settings = new Settings(dbHelper.getWritableDatabase());
settings.remove(StartupDialogFragment.HINT_GOOGLE_PLAY_ACCOUNTS_REMOVED);
settings.remove(StartupDialogFragment.HINT_BATTERY_OPTIMIZATIONS);
settings.remove(StartupDialogFragment.HINT_OPENTASKS_NOT_INSTALLED);
Snackbar.make(getView(), R.string.app_settings_reset_hints_success, Snackbar.LENGTH_LONG).show();
}

View File

@@ -17,6 +17,7 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
@@ -37,12 +38,14 @@ import lombok.Cleanup;
public class StartupDialogFragment extends DialogFragment {
public static final String
HINT_BATTERY_OPTIMIZATIONS = "hint_BatteryOptimizations",
HINT_GOOGLE_PLAY_ACCOUNTS_REMOVED = "hint_GooglePlayAccountsRemoved",
HINT_OPENTASKS_NOT_INSTALLED = "hint_OpenTasksNotInstalled";
private static final String ARGS_MODE = "mode";
enum Mode {
BATTERY_OPTIMIZATIONS,
DEVELOPMENT_VERSION,
FDROID_DONATE,
GOOGLE_PLAY_ACCOUNTS_REMOVED,
@@ -57,24 +60,18 @@ public class StartupDialogFragment extends DialogFragment {
if (BuildConfig.VERSION_NAME.contains("-alpha") || BuildConfig.VERSION_NAME.contains("-beta") || BuildConfig.VERSION_NAME.contains("-rc"))
dialogs.add(StartupDialogFragment.instantiate(Mode.DEVELOPMENT_VERSION));
else {
// store-specific information
if (BuildConfig.FLAVOR == App.FLAVOR_GOOGLE_PLAY) {
// Play store
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && // only on Android <5
settings.getBoolean(HINT_GOOGLE_PLAY_ACCOUNTS_REMOVED, true)) // and only when "Don't show again" hasn't been clicked yet
dialogs.add(StartupDialogFragment.instantiate(Mode.GOOGLE_PLAY_ACCOUNTS_REMOVED));
} else {
// other stores
final String installedFrom = installedFrom(context);
if (installedFrom == null || installedFrom.startsWith("org.fdroid"))
dialogs.add(StartupDialogFragment.instantiate(Mode.FDROID_DONATE));
}
else
dialogs.add(StartupDialogFragment.instantiate(Mode.FDROID_DONATE));
// battery optimization whitelisting
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && settings.getBoolean(HINT_BATTERY_OPTIMIZATIONS, true)) {
PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
if (!powerManager.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID))
dialogs.add(StartupDialogFragment.instantiate(Mode.BATTERY_OPTIMIZATIONS));
}
// OpenTasks information
if (!LocalTaskList.tasksProviderAvailable(context) &&
settings.getBoolean(HINT_OPENTASKS_NOT_INSTALLED, true))
if (!LocalTaskList.tasksProviderAvailable(context) && settings.getBoolean(HINT_OPENTASKS_NOT_INSTALLED, true))
dialogs.add(StartupDialogFragment.instantiate(Mode.OPENTASKS_NOT_INSTALLED));
Collections.reverse(dialogs);
@@ -98,6 +95,32 @@ public class StartupDialogFragment extends DialogFragment {
Mode mode = Mode.valueOf(getArguments().getString(ARGS_MODE));
switch (mode) {
case BATTERY_OPTIMIZATIONS:
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.startup_battery_optimization)
.setMessage(R.string.startup_battery_optimization_message)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setNeutralButton(R.string.startup_battery_optimization_disable, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
Uri.parse("package:" + BuildConfig.APPLICATION_ID));
getContext().startActivity(intent);
}
})
.setNegativeButton(R.string.startup_dont_show_again, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Settings settings = new Settings(dbHelper.getWritableDatabase());
settings.putBoolean(HINT_BATTERY_OPTIMIZATIONS, false);
}
})
.create();
case DEVELOPMENT_VERSION:
return new AlertDialog.Builder(getActivity())
.setIcon(R.drawable.ic_launcher)
@@ -117,54 +140,19 @@ public class StartupDialogFragment extends DialogFragment {
.create();
case FDROID_DONATE:
if (BuildConfig.FLAVOR != App.FLAVOR_GOOGLE_PLAY)
return new AlertDialog.Builder(getActivity())
.setIcon(R.drawable.ic_launcher)
.setTitle(R.string.startup_donate)
.setMessage(R.string.startup_donate_message)
.setPositiveButton(R.string.startup_donate_now, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startActivity(new Intent(Intent.ACTION_VIEW, Constants.webUri.buildUpon().appendEncodedPath("donate/").build()));
}
})
.setNegativeButton(R.string.startup_donate_later, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.create();
else
throw new IllegalArgumentException();
case GOOGLE_PLAY_ACCOUNTS_REMOVED:
Drawable icon = null;
try {
icon = getContext().getPackageManager().getApplicationIcon("com.android.vending").getCurrent();
} catch (PackageManager.NameNotFoundException e) {
App.log.log(Level.WARNING, "Can't load Play Store icon", e);
}
return new AlertDialog.Builder(getActivity())
.setIcon(icon)
.setTitle(R.string.startup_google_play_accounts_removed)
.setMessage(R.string.startup_google_play_accounts_removed_message)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
.setIcon(R.drawable.ic_launcher)
.setTitle(R.string.startup_donate)
.setMessage(R.string.startup_donate_message)
.setPositiveButton(R.string.startup_donate_now, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startActivity(new Intent(Intent.ACTION_VIEW, Constants.webUri.buildUpon().appendEncodedPath("donate/").build()));
}
})
.setNeutralButton(R.string.startup_google_play_accounts_removed_more_info, new DialogInterface.OnClickListener() {
.setNegativeButton(R.string.startup_donate_later, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Intent.ACTION_VIEW, Constants.webUri.buildUpon().appendEncodedPath("faq/").build());
getContext().startActivity(intent);
}
})
.setNegativeButton(R.string.startup_dont_show_again, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Settings settings = new Settings(dbHelper.getWritableDatabase());
settings.putBoolean(HINT_GOOGLE_PLAY_ACCOUNTS_REMOVED, false);
}
})
.create();

View File

@@ -157,9 +157,13 @@ public class AccountDetailsFragment extends Fragment {
settings.setSyncInterval(CalendarContract.AUTHORITY, DEFAULT_SYNC_INTERVAL);
// enable task sync, if possible
if (Build.VERSION.SDK_INT >= 23 || LocalTaskList.tasksProviderAvailable(getContext())) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
/* since Android 23, it's possible to gain OpenTasks permissions dynamically, so
* OpenTasks sync will be enabled by default. Setting the sync interval to "manually"
* if OpenTasks is not installed avoids the "sync error" in Android settings / Accounts. */
ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 1);
settings.setSyncInterval(TaskProvider.ProviderName.OpenTasks.authority, DEFAULT_SYNC_INTERVAL);
settings.setSyncInterval(TaskProvider.ProviderName.OpenTasks.authority,
LocalTaskList.tasksProviderAvailable(getContext()) ? DEFAULT_SYNC_INTERVAL : AccountSettings.SYNC_INTERVAL_MANUALLY);
} else
// Android <6 only: disable OpenTasks sync forever when OpenTasks is not installed
// because otherwise, there will be a non-catchable SecurityException as soon as OpenTasks is installed

View File

@@ -7,6 +7,9 @@
<string name="please_wait">Bitte warten …</string>
<string name="send">Senden</string>
<!--startup dialogs-->
<string name="startup_battery_optimization">Akku-Leistungsoptimierung</string>
<string name="startup_battery_optimization_message">Android kann die DAVdroid-Synchronisierung in ein paar Tagen reduzieren/deaktivieren. Um dies zu verhindern, muss die Akku-Leistungsoptimierung deaktiviert werden.</string>
<string name="startup_battery_optimization_disable">Für DAVdroid deaktivieren</string>
<string name="startup_dont_show_again">Nicht mehr anzeigen</string>
<string name="startup_development_version">DAVdroid Vorab-Version</string>
<string name="startup_development_version_message">Dies ist eine Vorschauversion von DAVdroid. Mit konstruktiven Rückmeldungen und Vorschlägen können Sie uns helfen, DAVdroid zu verbessern.</string>

View File

@@ -107,6 +107,7 @@
<string name="login_create_account">Maak een account</string>
<string name="login_account_name">Accountnaam</string>
<string name="login_account_name_info">Gebruik je email adres als account naam want Android zal je account naam gebruiken als ORGANIZER veld voor gemaakte afspraken. Je kunt geen 2 accounts met dezelfde naam hebben,</string>
<string name="login_account_contact_group_method">Contact groep methode:</string>
<string name="login_account_name_required">Accountnaam vereist</string>
<string name="login_account_not_created">Account kon niet gemaakt worden.</string>
<string name="login_configuration_detection">Configuratie detectie</string>
@@ -158,6 +159,19 @@
<string name="settings_sync_wifi_only_ssid_on">Zal alleen synchroniseren over %s</string>
<string name="settings_sync_wifi_only_ssid_off">Alle WiFI verbindingen mogen worden gebruikt</string>
<string name="settings_sync_wifi_only_ssid_message">Type de naam van het WiFi netwerk (SSID) om synchronisatie tot dit netwerk te beperken. Leeg laten voor sync over alle netwerken.</string>
<string name="settings_carddav">CardDAV</string>
<string name="settings_contact_group_method">Contact groep methode</string>
<string-array name="settings_contact_group_method_values">
<item>GROEP_VCARDS</item>
<item>CATEGORIES</item>
</string-array>
<string-array name="settings_contact_group_method_entries">
<item>Groepen zijn apparte VCards</item>
<item>Groepen zijn per-contact categories</item>
</string-array>
<string name="settings_rfc6868_for_vcards">Gebruik RFC6868 voor VCards</string>
<string name="settings_rfc6868_for_vcards_on">Aanhalingstekens kunnen worden gebruikt voor parameter waardes</string>
<string name="settings_rfc6868_for_vcards_off">Aanhalingstekens kunnen niet worden gebruikt voor parameter waardes</string>
<string name="settings_caldav">CalDAV</string>
<string name="settings_sync_time_range_past">Tijdslimiet verleden afspraken</string>
<string name="settings_sync_time_range_past_none">Alle afspraken worden gesynchronizeerd</string>
@@ -208,5 +222,19 @@
<string name="sync_error">Fout tijdens %s</string>
<string name="sync_error_http_dav">Serverfout tijdens %s</string>
<string name="sync_error_local_storage">Database fout tijdens %s</string>
<string-array name="sync_error_phases">
<item>synchronisatie voorbereiden</item>
<item>querying mogelijkheden</item>
<item>verwerken van lokaal verwijderde data</item>
<item>voorberteiding maken/wijzigen data</item>
<item>uploaden maken/bewerken data</item>
<item>controleren syngronisatie voortgang</item>
<item>lijst lokale data</item>
<item>lijst remote data</item>
<item>vergelijken lokale/remote data</item>
<item>downloaden remote data</item>
<item>nabewerking</item>
<item>opslaan sync voortgang</item>
</string-array>
<string name="sync_error_unauthorized">Gebruikersnaam/wachtwoord onjuist</string>
</resources>

View File

@@ -7,6 +7,9 @@
<string name="please_wait">Por favor, aguarde...</string>
<string name="send">Enviar</string>
<!--startup dialogs-->
<string name="startup_battery_optimization">Otimização da bateria</string>
<string name="startup_battery_optimization_message">O Android pode desativar/reduzir a sincronização do DAVdroid depois de alguns dias. Para evitar isso, desligue a otimização da bateria.</string>
<string name="startup_battery_optimization_disable">Desligar para o DAVdroid</string>
<string name="startup_dont_show_again">Não mostrar novamente</string>
<string name="startup_development_version">Versão prévia do DAVdroid</string>
<string name="startup_development_version_message">Esta é uma versão de desenvolvimento do DAVdroid. Lembre-se de que as coisas podem não funcionar como esperado. Por favor, envie sugestões e comentários construtivos para melhorar o DAVdroid.</string>

View File

@@ -7,6 +7,9 @@
<string name="please_wait">Сачекајте…</string>
<string name="send">Пошаљи</string>
<!--startup dialogs-->
<string name="startup_battery_optimization">Оптимизација батерије</string>
<string name="startup_battery_optimization_message">Андроид може да искључи/умањи синхронизацију ДАВдроида након неколико дана. Да бисте спречили ово, искључите оптимизацију батерије.</string>
<string name="startup_battery_optimization_disable">Искључи за ДАВдроид</string>
<string name="startup_dont_show_again">Не приказуј поново</string>
<string name="startup_development_version">ДАВдроид прелиминарно издање</string>
<string name="startup_development_version_message">Ово је развојно издање ДАВдроида. Имајте на уму да можда неће радити очекивано. Замољавамо вас за конструктивне повратне информације како бисмо га побољшали.</string>

View File

@@ -17,6 +17,9 @@
<string name="send">Send</string>
<!-- startup dialogs -->
<string name="startup_battery_optimization">Battery Optimization</string>
<string name="startup_battery_optimization_message">Android may disable/reduce DAVdroid synchronization after a few days. To prevent this, turn off battery optimization.</string>
<string name="startup_battery_optimization_disable">Turn off for DAVdroid</string>
<string name="startup_dont_show_again">Don\'t show again</string>
<string name="startup_development_version">DAVdroid Preview Release</string>
<string name="startup_development_version_message">This is a development version of DAVdroid. Be aware that things may not work as expected. Please give us constructive feedback to improve DAVdroid.</string>

View File

@@ -12,7 +12,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
classpath 'com.android.tools.build:gradle:2.1.2'
}
}