mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-27 12:26:48 +01:00
Make calendar blacklist configurable per device
This commit is contained in:
parent
7512147c34
commit
152f19575f
@ -117,7 +117,7 @@ public class GBApplication extends Application {
|
|||||||
private static SharedPreferences sharedPrefs;
|
private static SharedPreferences sharedPrefs;
|
||||||
private static final String PREFS_VERSION = "shared_preferences_version";
|
private static final String PREFS_VERSION = "shared_preferences_version";
|
||||||
//if preferences have to be migrated, increment the following and add the migration logic in migratePrefs below; see http://stackoverflow.com/questions/16397848/how-can-i-migrate-android-preferences-with-a-new-version
|
//if preferences have to be migrated, increment the following and add the migration logic in migratePrefs below; see http://stackoverflow.com/questions/16397848/how-can-i-migrate-android-preferences-with-a-new-version
|
||||||
private static final int CURRENT_PREFS_VERSION = 16;
|
private static final int CURRENT_PREFS_VERSION = 17;
|
||||||
|
|
||||||
private static LimitedQueue mIDSenderLookup = new LimitedQueue(16);
|
private static LimitedQueue mIDSenderLookup = new LimitedQueue(16);
|
||||||
private static Prefs prefs;
|
private static Prefs prefs;
|
||||||
@ -224,7 +224,6 @@ public class GBApplication extends Application {
|
|||||||
deviceService = createDeviceService();
|
deviceService = createDeviceService();
|
||||||
loadAppsNotifBlackList();
|
loadAppsNotifBlackList();
|
||||||
loadAppsPebbleBlackList();
|
loadAppsPebbleBlackList();
|
||||||
loadCalendarsBlackList();
|
|
||||||
|
|
||||||
PeriodicExporter.enablePeriodicExport(context);
|
PeriodicExporter.enablePeriodicExport(context);
|
||||||
|
|
||||||
@ -557,61 +556,6 @@ public class GBApplication extends Application {
|
|||||||
return packageName;
|
return packageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HashSet<String> calendars_blacklist = null;
|
|
||||||
|
|
||||||
public static boolean calendarIsBlacklisted(String calendarUniqueName) {
|
|
||||||
if (calendars_blacklist == null) {
|
|
||||||
GB.log("calendarIsBlacklisted: calendars_blacklist is null!", GB.INFO, null);
|
|
||||||
}
|
|
||||||
return calendars_blacklist != null && calendars_blacklist.contains(calendarUniqueName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setCalendarsBlackList(Set<String> calendarNames) {
|
|
||||||
if (calendarNames == null) {
|
|
||||||
GB.log("Set null apps_notification_blacklist", GB.INFO, null);
|
|
||||||
calendars_blacklist = new HashSet<>();
|
|
||||||
} else {
|
|
||||||
calendars_blacklist = new HashSet<>(calendarNames);
|
|
||||||
}
|
|
||||||
GB.log("New calendars_blacklist has " + calendars_blacklist.size() + " entries", GB.INFO, null);
|
|
||||||
saveCalendarsBlackList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addCalendarToBlacklist(String calendarUniqueName) {
|
|
||||||
if (calendars_blacklist.add(calendarUniqueName)) {
|
|
||||||
GB.log("Blacklisted calendar " + calendarUniqueName, GB.INFO, null);
|
|
||||||
saveCalendarsBlackList();
|
|
||||||
} else {
|
|
||||||
GB.log("Calendar " + calendarUniqueName + " already blacklisted!", GB.WARN, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void removeFromCalendarBlacklist(String calendarUniqueName) {
|
|
||||||
calendars_blacklist.remove(calendarUniqueName);
|
|
||||||
GB.log("Unblacklisted calendar " + calendarUniqueName, GB.INFO, null);
|
|
||||||
saveCalendarsBlackList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void loadCalendarsBlackList() {
|
|
||||||
GB.log("Loading calendars_blacklist", GB.INFO, null);
|
|
||||||
calendars_blacklist = (HashSet<String>) sharedPrefs.getStringSet(GBPrefs.CALENDAR_BLACKLIST, null); // lgtm [java/abstract-to-concrete-cast]
|
|
||||||
if (calendars_blacklist == null) {
|
|
||||||
calendars_blacklist = new HashSet<>();
|
|
||||||
}
|
|
||||||
GB.log("Loaded calendars_blacklist has " + calendars_blacklist.size() + " entries", GB.INFO, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void saveCalendarsBlackList() {
|
|
||||||
GB.log("Saving calendars_blacklist with " + calendars_blacklist.size() + " entries", GB.INFO, null);
|
|
||||||
SharedPreferences.Editor editor = sharedPrefs.edit();
|
|
||||||
if (calendars_blacklist.isEmpty()) {
|
|
||||||
editor.putStringSet(GBPrefs.CALENDAR_BLACKLIST, null);
|
|
||||||
} else {
|
|
||||||
Prefs.putStringSet(editor, GBPrefs.CALENDAR_BLACKLIST, calendars_blacklist);
|
|
||||||
}
|
|
||||||
editor.apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes both the old Activity database and the new one recreates it with empty tables.
|
* Deletes both the old Activity database and the new one recreates it with empty tables.
|
||||||
*
|
*
|
||||||
@ -1190,6 +1134,32 @@ public class GBApplication extends Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < 17) {
|
||||||
|
final HashSet<String> calendarBlacklist = (HashSet<String>) prefs.getStringSet(GBPrefs.CALENDAR_BLACKLIST, null);
|
||||||
|
|
||||||
|
try (DBHandler db = acquireDB()) {
|
||||||
|
final DaoSession daoSession = db.getDaoSession();
|
||||||
|
final List<Device> activeDevices = DBHelper.getActiveDevices(daoSession);
|
||||||
|
|
||||||
|
for (Device dbDevice : activeDevices) {
|
||||||
|
final SharedPreferences deviceSharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(dbDevice.getIdentifier());
|
||||||
|
final SharedPreferences.Editor deviceSharedPrefsEdit = deviceSharedPrefs.edit();
|
||||||
|
|
||||||
|
deviceSharedPrefsEdit.putBoolean("sync_calendar", prefs.getBoolean("enable_calendar_sync", true));
|
||||||
|
|
||||||
|
if (calendarBlacklist != null) {
|
||||||
|
Prefs.putStringSet(deviceSharedPrefsEdit, GBPrefs.CALENDAR_BLACKLIST, calendarBlacklist);
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceSharedPrefsEdit.apply();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.w(TAG, "error acquiring DB lock");
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.remove(GBPrefs.CALENDAR_BLACKLIST);
|
||||||
|
}
|
||||||
|
|
||||||
editor.putString(PREFS_VERSION, Integer.toString(CURRENT_PREFS_VERSION));
|
editor.putString(PREFS_VERSION, Integer.toString(CURRENT_PREFS_VERSION));
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,9 @@ import androidx.core.app.ActivityCompat;
|
|||||||
import androidx.core.app.NavUtils;
|
import androidx.core.app.NavUtils;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarManager;
|
||||||
|
|
||||||
|
|
||||||
public class CalBlacklistActivity extends AbstractGBActivity {
|
public class CalBlacklistActivity extends AbstractGBActivity {
|
||||||
@ -56,12 +58,18 @@ public class CalBlacklistActivity extends AbstractGBActivity {
|
|||||||
};
|
};
|
||||||
private ArrayList<Calendar> calendarsArrayList;
|
private ArrayList<Calendar> calendarsArrayList;
|
||||||
|
|
||||||
|
private GBDevice gbDevice;
|
||||||
|
private CalendarManager calendarManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_calblacklist);
|
setContentView(R.layout.activity_calblacklist);
|
||||||
ListView calListView = (ListView) findViewById(R.id.calListView);
|
ListView calListView = (ListView) findViewById(R.id.calListView);
|
||||||
|
|
||||||
|
gbDevice = getIntent().getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||||
|
calendarManager = new CalendarManager(this, gbDevice.getAddress());
|
||||||
|
|
||||||
final Uri uri = CalendarContract.Calendars.CONTENT_URI;
|
final Uri uri = CalendarContract.Calendars.CONTENT_URI;
|
||||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) != PackageManager.PERMISSION_GRANTED) {
|
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) != PackageManager.PERMISSION_GRANTED) {
|
||||||
GB.toast(this, "Calendar permission not granted. Nothing to do.", Toast.LENGTH_SHORT, GB.WARN);
|
GB.toast(this, "Calendar permission not granted. Nothing to do.", Toast.LENGTH_SHORT, GB.WARN);
|
||||||
@ -83,9 +91,9 @@ public class CalBlacklistActivity extends AbstractGBActivity {
|
|||||||
CheckBox selected = (CheckBox) view.findViewById(R.id.item_checkbox);
|
CheckBox selected = (CheckBox) view.findViewById(R.id.item_checkbox);
|
||||||
toggleEntry(view);
|
toggleEntry(view);
|
||||||
if (selected.isChecked()) {
|
if (selected.isChecked()) {
|
||||||
GBApplication.addCalendarToBlacklist(item.getUniqueString());
|
calendarManager.addCalendarToBlacklist(item.getUniqueString());
|
||||||
} else {
|
} else {
|
||||||
GBApplication.removeFromCalendarBlacklist(item.getUniqueString());
|
calendarManager.removeFromCalendarBlacklist(item.getUniqueString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -148,8 +156,8 @@ public class CalBlacklistActivity extends AbstractGBActivity {
|
|||||||
TextView ownerAccount = (TextView) view.findViewById(R.id.calendar_owner_account);
|
TextView ownerAccount = (TextView) view.findViewById(R.id.calendar_owner_account);
|
||||||
CheckBox checked = (CheckBox) view.findViewById(R.id.item_checkbox);
|
CheckBox checked = (CheckBox) view.findViewById(R.id.item_checkbox);
|
||||||
|
|
||||||
if (GBApplication.calendarIsBlacklisted(item.getUniqueString()) && !checked.isChecked() ||
|
if (calendarManager.calendarIsBlacklisted(item.getUniqueString()) && !checked.isChecked() ||
|
||||||
!GBApplication.calendarIsBlacklisted(item.getUniqueString()) && checked.isChecked()) {
|
!calendarManager.calendarIsBlacklisted(item.getUniqueString()) && checked.isChecked()) {
|
||||||
toggleEntry(view);
|
toggleEntry(view);
|
||||||
}
|
}
|
||||||
color.setBackgroundColor(item.color);
|
color.setBackgroundColor(item.color);
|
||||||
|
@ -138,15 +138,6 @@ public class SettingsActivity extends AbstractSettingsActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
pref = findPreference("pref_key_blacklist_calendars");
|
|
||||||
pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
|
||||||
Intent enableIntent = new Intent(SettingsActivity.this, CalBlacklistActivity.class);
|
|
||||||
startActivity(enableIntent);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
pref = findPreference("pebble_emu_addr");
|
pref = findPreference("pebble_emu_addr");
|
||||||
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -49,7 +49,9 @@ import java.util.Set;
|
|||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.CalBlacklistActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureWorldClocks;
|
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureWorldClocks;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.SettingsActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
|
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiConst;
|
||||||
@ -688,6 +690,18 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final Preference calendarBlacklist = findPreference("blacklist_calendars");
|
||||||
|
if (calendarBlacklist != null) {
|
||||||
|
calendarBlacklist.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||||
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
Intent intent = new Intent(getContext(), CalBlacklistActivity.class);
|
||||||
|
intent.putExtra(GBDevice.EXTRA_DEVICE, device);
|
||||||
|
startActivity(intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
final Preference cannedMessagesDismissCall = findPreference("canned_messages_dismisscall_send");
|
final Preference cannedMessagesDismissCall = findPreference("canned_messages_dismisscall_send");
|
||||||
if (cannedMessagesDismissCall != null) {
|
if (cannedMessagesDismissCall != null) {
|
||||||
cannedMessagesDismissCall.setOnPreferenceClickListener(new androidx.preference.Preference.OnPreferenceClickListener() {
|
cannedMessagesDismissCall.setOnPreferenceClickListener(new androidx.preference.Preference.OnPreferenceClickListener() {
|
||||||
|
@ -230,6 +230,7 @@ public class PebbleCoordinator extends AbstractDeviceCoordinator {
|
|||||||
R.xml.devicesettings_autoremove_notifications,
|
R.xml.devicesettings_autoremove_notifications,
|
||||||
R.xml.devicesettings_canned_reply_16,
|
R.xml.devicesettings_canned_reply_16,
|
||||||
R.xml.devicesettings_canned_dismisscall_16,
|
R.xml.devicesettings_canned_dismisscall_16,
|
||||||
|
R.xml.devicesettings_sync_calendar,
|
||||||
R.xml.devicesettings_transliteration
|
R.xml.devicesettings_transliteration
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,8 @@ import nodomain.freeyourgadget.gadgetbridge.entities.CalendarSyncStateDao;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEvents;
|
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarEvent;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarManager;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
public class CalendarReceiver extends BroadcastReceiver {
|
public class CalendarReceiver extends BroadcastReceiver {
|
||||||
@ -52,9 +53,9 @@ public class CalendarReceiver extends BroadcastReceiver {
|
|||||||
|
|
||||||
private class EventSyncState {
|
private class EventSyncState {
|
||||||
private int state;
|
private int state;
|
||||||
private CalendarEvents.CalendarEvent event;
|
private CalendarEvent event;
|
||||||
|
|
||||||
EventSyncState(CalendarEvents.CalendarEvent event, int state) {
|
EventSyncState(CalendarEvent event, int state) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.event = event;
|
this.event = event;
|
||||||
}
|
}
|
||||||
@ -67,11 +68,11 @@ public class CalendarReceiver extends BroadcastReceiver {
|
|||||||
this.state = state;
|
this.state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CalendarEvents.CalendarEvent getEvent() {
|
public CalendarEvent getEvent() {
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEvent(CalendarEvents.CalendarEvent event) {
|
public void setEvent(CalendarEvent event) {
|
||||||
this.event = event;
|
this.event = event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,11 +93,11 @@ public class CalendarReceiver extends BroadcastReceiver {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
LOG.info("got calendar changed broadcast");
|
LOG.info("got calendar changed broadcast");
|
||||||
List<CalendarEvents.CalendarEvent> eventList = (new CalendarEvents()).getCalendarEventList(GBApplication.getContext());
|
List<CalendarEvent> eventList = (new CalendarManager(context, mGBDevice.getAddress())).getCalendarEventList();
|
||||||
syncCalendar(eventList);
|
syncCalendar(eventList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void syncCalendar(List<CalendarEvents.CalendarEvent> eventList) {
|
public void syncCalendar(List<CalendarEvent> eventList) {
|
||||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||||
DaoSession session = dbHandler.getDaoSession();
|
DaoSession session = dbHandler.getDaoSession();
|
||||||
syncCalendar(eventList, session);
|
syncCalendar(eventList, session);
|
||||||
@ -105,14 +106,14 @@ public class CalendarReceiver extends BroadcastReceiver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void syncCalendar(List<CalendarEvents.CalendarEvent> eventList, DaoSession session) {
|
public void syncCalendar(List<CalendarEvent> eventList, DaoSession session) {
|
||||||
LOG.info("Syncing with calendar.");
|
LOG.info("Syncing with calendar.");
|
||||||
Hashtable<Long, CalendarEvents.CalendarEvent> eventTable = new Hashtable<>();
|
Hashtable<Long, CalendarEvent> eventTable = new Hashtable<>();
|
||||||
Long deviceId = DBHelper.getDevice(mGBDevice, session).getId();
|
Long deviceId = DBHelper.getDevice(mGBDevice, session).getId();
|
||||||
QueryBuilder<CalendarSyncState> qb = session.getCalendarSyncStateDao().queryBuilder();
|
QueryBuilder<CalendarSyncState> qb = session.getCalendarSyncStateDao().queryBuilder();
|
||||||
|
|
||||||
|
|
||||||
for (CalendarEvents.CalendarEvent e : eventList) {
|
for (CalendarEvent e : eventList) {
|
||||||
long id = e.getId();
|
long id = e.getId();
|
||||||
eventTable.put(id, e);
|
eventTable.put(id, e);
|
||||||
if (!eventState.containsKey(e.getId())) {
|
if (!eventState.containsKey(e.getId())) {
|
||||||
@ -176,7 +177,7 @@ public class CalendarReceiver extends BroadcastReceiver {
|
|||||||
EventSyncState es = eventState.get(i);
|
EventSyncState es = eventState.get(i);
|
||||||
int syncState = es.getState();
|
int syncState = es.getState();
|
||||||
if (syncState == EventState.NOT_SYNCED || syncState == EventState.NEEDS_UPDATE) {
|
if (syncState == EventState.NOT_SYNCED || syncState == EventState.NEEDS_UPDATE) {
|
||||||
CalendarEvents.CalendarEvent calendarEvent = es.getEvent();
|
CalendarEvent calendarEvent = es.getEvent();
|
||||||
CalendarEventSpec calendarEventSpec = new CalendarEventSpec();
|
CalendarEventSpec calendarEventSpec = new CalendarEventSpec();
|
||||||
calendarEventSpec.id = i;
|
calendarEventSpec.id = i;
|
||||||
calendarEventSpec.title = calendarEvent.getTitle();
|
calendarEventSpec.title = calendarEvent.getTitle();
|
||||||
|
@ -1,244 +0,0 @@
|
|||||||
/* Copyright (C) 2015-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
|
||||||
Gobbetti, Daniel Hauck
|
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
|
||||||
|
|
||||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as published
|
|
||||||
by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Gadgetbridge is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
||||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
|
||||||
|
|
||||||
import android.content.ContentUris;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.provider.CalendarContract;
|
|
||||||
import android.provider.CalendarContract.Instances;
|
|
||||||
import android.text.format.Time;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
|
||||||
|
|
||||||
public class CalendarEvents {
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(CalendarEvents.class);
|
|
||||||
|
|
||||||
// needed for pebble: time, duration, layout, reminders, actions
|
|
||||||
// layout: type, title, subtitle, body (max 512), tinyIcon, smallIcon, largeIcon
|
|
||||||
//further: primaryColor, secondaryColor, backgroundColor, headings, paragraphs, lastUpdated
|
|
||||||
// taken from: https://developer.getpebble.com/guides/timeline/pin-structure/
|
|
||||||
|
|
||||||
// needed for MiBand:
|
|
||||||
// time
|
|
||||||
|
|
||||||
private static final String[] EVENT_INSTANCE_PROJECTION = new String[]{
|
|
||||||
Instances._ID,
|
|
||||||
|
|
||||||
Instances.BEGIN,
|
|
||||||
Instances.END,
|
|
||||||
Instances.DURATION,
|
|
||||||
Instances.TITLE,
|
|
||||||
Instances.DESCRIPTION,
|
|
||||||
Instances.EVENT_LOCATION,
|
|
||||||
Instances.CALENDAR_DISPLAY_NAME,
|
|
||||||
CalendarContract.Calendars.ACCOUNT_NAME,
|
|
||||||
Instances.CALENDAR_COLOR,
|
|
||||||
Instances.ALL_DAY
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final int lookahead_days = 7;
|
|
||||||
|
|
||||||
private List<CalendarEvent> calendarEventList = new ArrayList<CalendarEvent>();
|
|
||||||
|
|
||||||
public List<CalendarEvent> getCalendarEventList(Context mContext) {
|
|
||||||
fetchSystemEvents(mContext);
|
|
||||||
return calendarEventList;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean fetchSystemEvents(Context mContext) {
|
|
||||||
|
|
||||||
Calendar cal = GregorianCalendar.getInstance();
|
|
||||||
long dtStart = cal.getTimeInMillis();
|
|
||||||
cal.add(Calendar.DATE, lookahead_days);
|
|
||||||
long dtEnd = cal.getTimeInMillis();
|
|
||||||
|
|
||||||
Uri.Builder eventsUriBuilder = Instances.CONTENT_URI.buildUpon();
|
|
||||||
ContentUris.appendId(eventsUriBuilder, dtStart);
|
|
||||||
ContentUris.appendId(eventsUriBuilder, dtEnd);
|
|
||||||
Uri eventsUri = eventsUriBuilder.build();
|
|
||||||
|
|
||||||
try (Cursor evtCursor = mContext.getContentResolver().query(eventsUri, EVENT_INSTANCE_PROJECTION, null, null, Instances.BEGIN + " ASC")) {
|
|
||||||
if (evtCursor == null || evtCursor.getCount() == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
while (evtCursor.moveToNext()) {
|
|
||||||
long start = evtCursor.getLong(1);
|
|
||||||
long end = evtCursor.getLong(2);
|
|
||||||
if (end == 0) {
|
|
||||||
LOG.info("no end time, will parse duration string");
|
|
||||||
Time time = new Time(); //FIXME: deprecated FTW
|
|
||||||
time.parse(evtCursor.getString(3));
|
|
||||||
end = start + time.toMillis(false);
|
|
||||||
}
|
|
||||||
CalendarEvent calEvent = new CalendarEvent(
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
evtCursor.getLong(0),
|
|
||||||
evtCursor.getString(4),
|
|
||||||
evtCursor.getString(5),
|
|
||||||
evtCursor.getString(6),
|
|
||||||
evtCursor.getString(7),
|
|
||||||
evtCursor.getString(8),
|
|
||||||
evtCursor.getInt(9),
|
|
||||||
!evtCursor.getString(10).equals("0")
|
|
||||||
);
|
|
||||||
if (!GBApplication.calendarIsBlacklisted(calEvent.getUniqueCalName())) {
|
|
||||||
calendarEventList.add(calEvent);
|
|
||||||
} else {
|
|
||||||
LOG.debug("calendar " + calEvent.getUniqueCalName() + " skipped because it's blacklisted");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.error("could not query calendar, permission denied?");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class CalendarEvent {
|
|
||||||
private long begin;
|
|
||||||
private long end;
|
|
||||||
private long id;
|
|
||||||
private String title;
|
|
||||||
private String description;
|
|
||||||
private String location;
|
|
||||||
private String calName;
|
|
||||||
private String calAccountName;
|
|
||||||
private int color;
|
|
||||||
private boolean allDay;
|
|
||||||
|
|
||||||
public CalendarEvent(long begin, long end, long id, String title, String description, String location, String calName, String calAccountName, int color, boolean allDay) {
|
|
||||||
this.begin = begin;
|
|
||||||
this.end = end;
|
|
||||||
this.id = id;
|
|
||||||
this.title = title;
|
|
||||||
this.description = description;
|
|
||||||
this.location = location;
|
|
||||||
this.calName = calName;
|
|
||||||
this.calAccountName = calAccountName;
|
|
||||||
this.color = color;
|
|
||||||
this.allDay = allDay;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getBegin() {
|
|
||||||
return begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getBeginSeconds() {
|
|
||||||
return (int) (begin / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getEnd() {
|
|
||||||
return end;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getDuration() {
|
|
||||||
return end - begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDurationSeconds() {
|
|
||||||
return (int) ((getDuration()) / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public short getDurationMinutes() {
|
|
||||||
return (short) (getDurationSeconds() / 60);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTitle() {
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLocation() {
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCalName() {
|
|
||||||
return calName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCalAccountName() {
|
|
||||||
return calAccountName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUniqueCalName() {
|
|
||||||
return getCalAccountName() + '/' + getCalName();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getColor() {
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAllDay() {
|
|
||||||
return allDay;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object other) {
|
|
||||||
if (other instanceof CalendarEvent) {
|
|
||||||
CalendarEvent e = (CalendarEvent) other;
|
|
||||||
return (this.getId() == e.getId()) &&
|
|
||||||
Objects.equals(this.getTitle(), e.getTitle()) &&
|
|
||||||
(this.getBegin() == e.getBegin()) &&
|
|
||||||
Objects.equals(this.getLocation(), e.getLocation()) &&
|
|
||||||
Objects.equals(this.getDescription(), e.getDescription()) &&
|
|
||||||
(this.getEnd() == e.getEnd()) &&
|
|
||||||
Objects.equals(this.getCalName(), e.getCalName()) &&
|
|
||||||
Objects.equals(this.getCalAccountName(), e.getCalAccountName()) &&
|
|
||||||
(this.getColor() == e.getColor()) &&
|
|
||||||
(this.isAllDay() == e.isAllDay());
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int result = (int) id;
|
|
||||||
result = 31 * result + Objects.hash(title);
|
|
||||||
result = 31 * result + Long.valueOf(begin).hashCode();
|
|
||||||
result = 31 * result + Objects.hash(location);
|
|
||||||
result = 31 * result + Objects.hash(description);
|
|
||||||
result = 31 * result + Long.valueOf(end).hashCode();
|
|
||||||
result = 31 * result + Objects.hash(calName);
|
|
||||||
result = 31 * result + Objects.hash(calAccountName);
|
|
||||||
result = 31 * result + Integer.valueOf(color).hashCode();
|
|
||||||
result = 31 * result + Boolean.valueOf(allDay).hashCode();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -976,7 +976,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (enable && initialized && features.supportsCalendarEvents()) {
|
if (enable && initialized && features.supportsCalendarEvents()) {
|
||||||
if (mCalendarReceiver == null && getPrefs().getBoolean("enable_calendar_sync", true)) {
|
if (mCalendarReceiver == null) {
|
||||||
if (!(GBApplication.isRunningMarshmallowOrLater() && ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_DENIED)) {
|
if (!(GBApplication.isRunningMarshmallowOrLater() && ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_DENIED)) {
|
||||||
IntentFilter calendarIntentFilter = new IntentFilter();
|
IntentFilter calendarIntentFilter = new IntentFilter();
|
||||||
calendarIntentFilter.addAction("android.intent.action.PROVIDER_CHANGED");
|
calendarIntentFilter.addAction("android.intent.action.PROVIDER_CHANGED");
|
||||||
|
@ -110,7 +110,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEvents;
|
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarEvent;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarManager;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
||||||
@ -2509,12 +2510,12 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport {
|
|||||||
int availableSlots = prefs.getInt(PREF_RESERVER_ALARMS_CALENDAR, 0);
|
int availableSlots = prefs.getInt(PREF_RESERVER_ALARMS_CALENDAR, 0);
|
||||||
|
|
||||||
if (availableSlots > 0) {
|
if (availableSlots > 0) {
|
||||||
CalendarEvents upcomingEvents = new CalendarEvents();
|
CalendarManager upcomingEvents = new CalendarManager(getContext(), getDevice().getAddress());
|
||||||
List<CalendarEvents.CalendarEvent> mEvents = upcomingEvents.getCalendarEventList(getContext());
|
List<CalendarEvent> mEvents = upcomingEvents.getCalendarEventList();
|
||||||
|
|
||||||
int iteration = 0;
|
int iteration = 0;
|
||||||
|
|
||||||
for (CalendarEvents.CalendarEvent mEvt : mEvents) {
|
for (CalendarEvent mEvt : mEvents) {
|
||||||
if (mEvt.isAllDay()) {
|
if (mEvt.isAllDay()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -2541,13 +2542,13 @@ public abstract class HuamiSupport extends AbstractBTLEDeviceSupport {
|
|||||||
final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
|
final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()));
|
||||||
int availableSlots = prefs.getInt(PREF_RESERVER_REMINDERS_CALENDAR, 9);
|
int availableSlots = prefs.getInt(PREF_RESERVER_REMINDERS_CALENDAR, 9);
|
||||||
|
|
||||||
CalendarEvents upcomingEvents = new CalendarEvents();
|
CalendarManager upcomingEvents = new CalendarManager(getContext(), getDevice().getAddress());
|
||||||
List<CalendarEvents.CalendarEvent> calendarEvents = upcomingEvents.getCalendarEventList(getContext());
|
List<CalendarEvent> calendarEvents = upcomingEvents.getCalendarEventList();
|
||||||
Calendar calendar = Calendar.getInstance();
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
|
||||||
int iteration = 0;
|
int iteration = 0;
|
||||||
|
|
||||||
for (CalendarEvents.CalendarEvent calendarEvent : calendarEvents) {
|
for (CalendarEvent calendarEvent : calendarEvents) {
|
||||||
if (calendarEvent.isAllDay()) {
|
if (calendarEvent.isAllDay()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEvents;
|
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarEvent;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarManager;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
||||||
@ -1233,11 +1234,11 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
|||||||
availableSlots = 3;
|
availableSlots = 3;
|
||||||
}
|
}
|
||||||
if (availableSlots > 0) {
|
if (availableSlots > 0) {
|
||||||
CalendarEvents upcomingEvents = new CalendarEvents();
|
CalendarManager upcomingEvents = new CalendarManager(getContext(), getDevice().getAddress());
|
||||||
List<CalendarEvents.CalendarEvent> mEvents = upcomingEvents.getCalendarEventList(getContext());
|
List<CalendarEvent> mEvents = upcomingEvents.getCalendarEventList();
|
||||||
|
|
||||||
int iteration = 0;
|
int iteration = 0;
|
||||||
for (CalendarEvents.CalendarEvent mEvt : mEvents) {
|
for (CalendarEvent mEvt : mEvents) {
|
||||||
if (iteration >= availableSlots) {
|
if (iteration >= availableSlots) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
|
import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEvents;
|
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarEvent;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||||
@ -73,6 +73,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarManager;
|
||||||
|
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SYNC_CALENDAR;
|
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_SYNC_CALENDAR;
|
||||||
|
|
||||||
@ -594,11 +595,11 @@ public class ZeTimeDeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CalendarEvents upcomingEvents = new CalendarEvents();
|
CalendarManager upcomingEvents = new CalendarManager(getContext(), getDevice().getAddress());
|
||||||
List<CalendarEvents.CalendarEvent> calendarEvents = upcomingEvents.getCalendarEventList(getContext());
|
List<CalendarEvent> calendarEvents = upcomingEvents.getCalendarEventList();
|
||||||
|
|
||||||
int eventCount = 0;
|
int eventCount = 0;
|
||||||
for (CalendarEvents.CalendarEvent calendarEvent : calendarEvents) {
|
for (CalendarEvent calendarEvent : calendarEvents) {
|
||||||
if (calendarEvent.isAllDay()) {
|
if (calendarEvent.isAllDay()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -134,14 +134,6 @@ public class ImportExportSharedPreferences {
|
|||||||
}
|
}
|
||||||
GBApplication.setAppsPebbleBlackList(apps_pebble_blacklist);
|
GBApplication.setAppsPebbleBlackList(apps_pebble_blacklist);
|
||||||
break;
|
break;
|
||||||
case GBPrefs.CALENDAR_BLACKLIST: //TODO: untested
|
|
||||||
Set<String> calendars_blacklist = new HashSet<>();
|
|
||||||
text = text.replace("[", "").replace("]", "");
|
|
||||||
for (int z = 0; z < text.split(",").length; z++) {
|
|
||||||
calendars_blacklist.add(text.split(",")[z].trim());
|
|
||||||
}
|
|
||||||
GBApplication.setCalendarsBlackList(calendars_blacklist);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else if (!PREFERENCES.equals(name)) {
|
} else if (!PREFERENCES.equals(name)) {
|
||||||
throw new Exception("Unknown type " + name);
|
throw new Exception("Unknown type " + name);
|
||||||
|
@ -0,0 +1,141 @@
|
|||||||
|
/* Copyright (C) 2017-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti, Daniel Hauck
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.util.calendar;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class CalendarEvent {
|
||||||
|
private long begin;
|
||||||
|
private long end;
|
||||||
|
private long id;
|
||||||
|
private String title;
|
||||||
|
private String description;
|
||||||
|
private String location;
|
||||||
|
private String calName;
|
||||||
|
private String calAccountName;
|
||||||
|
private int color;
|
||||||
|
private boolean allDay;
|
||||||
|
|
||||||
|
public CalendarEvent(long begin, long end, long id, String title, String description, String location, String calName, String calAccountName, int color, boolean allDay) {
|
||||||
|
this.begin = begin;
|
||||||
|
this.end = end;
|
||||||
|
this.id = id;
|
||||||
|
this.title = title;
|
||||||
|
this.description = description;
|
||||||
|
this.location = location;
|
||||||
|
this.calName = calName;
|
||||||
|
this.calAccountName = calAccountName;
|
||||||
|
this.color = color;
|
||||||
|
this.allDay = allDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getBegin() {
|
||||||
|
return begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBeginSeconds() {
|
||||||
|
return (int) (begin / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getEnd() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDuration() {
|
||||||
|
return end - begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDurationSeconds() {
|
||||||
|
return (int) ((getDuration()) / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getDurationMinutes() {
|
||||||
|
return (short) (getDurationSeconds() / 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCalName() {
|
||||||
|
return calName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCalAccountName() {
|
||||||
|
return calAccountName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUniqueCalName() {
|
||||||
|
return getCalAccountName() + '/' + getCalName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAllDay() {
|
||||||
|
return allDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (other instanceof CalendarEvent) {
|
||||||
|
CalendarEvent e = (CalendarEvent) other;
|
||||||
|
return (this.getId() == e.getId()) &&
|
||||||
|
Objects.equals(this.getTitle(), e.getTitle()) &&
|
||||||
|
(this.getBegin() == e.getBegin()) &&
|
||||||
|
Objects.equals(this.getLocation(), e.getLocation()) &&
|
||||||
|
Objects.equals(this.getDescription(), e.getDescription()) &&
|
||||||
|
(this.getEnd() == e.getEnd()) &&
|
||||||
|
Objects.equals(this.getCalName(), e.getCalName()) &&
|
||||||
|
Objects.equals(this.getCalAccountName(), e.getCalAccountName()) &&
|
||||||
|
(this.getColor() == e.getColor()) &&
|
||||||
|
(this.isAllDay() == e.isAllDay());
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = (int) id;
|
||||||
|
result = 31 * result + Objects.hash(title);
|
||||||
|
result = 31 * result + Long.valueOf(begin).hashCode();
|
||||||
|
result = 31 * result + Objects.hash(location);
|
||||||
|
result = 31 * result + Objects.hash(description);
|
||||||
|
result = 31 * result + Long.valueOf(end).hashCode();
|
||||||
|
result = 31 * result + Objects.hash(calName);
|
||||||
|
result = 31 * result + Objects.hash(calAccountName);
|
||||||
|
result = 31 * result + Integer.valueOf(color).hashCode();
|
||||||
|
result = 31 * result + Boolean.valueOf(allDay).hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,193 @@
|
|||||||
|
/* Copyright (C) 2015-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti, Daniel Hauck
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.util.calendar;
|
||||||
|
|
||||||
|
import android.content.ContentUris;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.provider.CalendarContract;
|
||||||
|
import android.provider.CalendarContract.Instances;
|
||||||
|
import android.text.format.Time;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
|
|
||||||
|
public class CalendarManager {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(CalendarManager.class);
|
||||||
|
|
||||||
|
// needed for pebble: time, duration, layout, reminders, actions
|
||||||
|
// layout: type, title, subtitle, body (max 512), tinyIcon, smallIcon, largeIcon
|
||||||
|
//further: primaryColor, secondaryColor, backgroundColor, headings, paragraphs, lastUpdated
|
||||||
|
// taken from: https://developer.getpebble.com/guides/timeline/pin-structure/
|
||||||
|
|
||||||
|
// needed for MiBand:
|
||||||
|
// time
|
||||||
|
|
||||||
|
private static final String[] EVENT_INSTANCE_PROJECTION = new String[]{
|
||||||
|
Instances._ID,
|
||||||
|
|
||||||
|
Instances.BEGIN,
|
||||||
|
Instances.END,
|
||||||
|
Instances.DURATION,
|
||||||
|
Instances.TITLE,
|
||||||
|
Instances.DESCRIPTION,
|
||||||
|
Instances.EVENT_LOCATION,
|
||||||
|
Instances.CALENDAR_DISPLAY_NAME,
|
||||||
|
CalendarContract.Calendars.ACCOUNT_NAME,
|
||||||
|
Instances.CALENDAR_COLOR,
|
||||||
|
Instances.ALL_DAY
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final int lookahead_days = 7;
|
||||||
|
|
||||||
|
private final String deviceAddress;
|
||||||
|
private final Context mContext;
|
||||||
|
|
||||||
|
public CalendarManager(final Context context, final String deviceAddress) {
|
||||||
|
this.mContext = context;
|
||||||
|
this.deviceAddress = deviceAddress;
|
||||||
|
|
||||||
|
loadCalendarsBlackList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<CalendarEvent> getCalendarEventList() {
|
||||||
|
loadCalendarsBlackList();
|
||||||
|
|
||||||
|
final List<CalendarEvent> calendarEventList = new ArrayList<CalendarEvent>();
|
||||||
|
|
||||||
|
Calendar cal = GregorianCalendar.getInstance();
|
||||||
|
long dtStart = cal.getTimeInMillis();
|
||||||
|
cal.add(Calendar.DATE, lookahead_days);
|
||||||
|
long dtEnd = cal.getTimeInMillis();
|
||||||
|
|
||||||
|
Uri.Builder eventsUriBuilder = Instances.CONTENT_URI.buildUpon();
|
||||||
|
ContentUris.appendId(eventsUriBuilder, dtStart);
|
||||||
|
ContentUris.appendId(eventsUriBuilder, dtEnd);
|
||||||
|
Uri eventsUri = eventsUriBuilder.build();
|
||||||
|
|
||||||
|
try (Cursor evtCursor = mContext.getContentResolver().query(eventsUri, EVENT_INSTANCE_PROJECTION, null, null, Instances.BEGIN + " ASC")) {
|
||||||
|
if (evtCursor == null || evtCursor.getCount() == 0) {
|
||||||
|
return calendarEventList;
|
||||||
|
}
|
||||||
|
while (evtCursor.moveToNext()) {
|
||||||
|
long start = evtCursor.getLong(1);
|
||||||
|
long end = evtCursor.getLong(2);
|
||||||
|
if (end == 0) {
|
||||||
|
LOG.info("no end time, will parse duration string");
|
||||||
|
Time time = new Time(); //FIXME: deprecated FTW
|
||||||
|
time.parse(evtCursor.getString(3));
|
||||||
|
end = start + time.toMillis(false);
|
||||||
|
}
|
||||||
|
CalendarEvent calEvent = new CalendarEvent(
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
evtCursor.getLong(0),
|
||||||
|
evtCursor.getString(4),
|
||||||
|
evtCursor.getString(5),
|
||||||
|
evtCursor.getString(6),
|
||||||
|
evtCursor.getString(7),
|
||||||
|
evtCursor.getString(8),
|
||||||
|
evtCursor.getInt(9),
|
||||||
|
!evtCursor.getString(10).equals("0")
|
||||||
|
);
|
||||||
|
if (!calendarIsBlacklisted(calEvent.getUniqueCalName())) {
|
||||||
|
calendarEventList.add(calEvent);
|
||||||
|
} else {
|
||||||
|
LOG.debug("calendar {} skipped because it's blacklisted", calEvent.getUniqueCalName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return calendarEventList;
|
||||||
|
} catch (final Exception e) {
|
||||||
|
LOG.error("could not query calendar, permission denied?", e);
|
||||||
|
return calendarEventList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HashSet<String> calendars_blacklist = null;
|
||||||
|
|
||||||
|
public boolean calendarIsBlacklisted(String calendarUniqueName) {
|
||||||
|
if (calendars_blacklist == null) {
|
||||||
|
LOG.warn("calendarIsBlacklisted: calendars_blacklist is null!");
|
||||||
|
}
|
||||||
|
return calendars_blacklist != null && calendars_blacklist.contains(calendarUniqueName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCalendarsBlackList(Set<String> calendarNames) {
|
||||||
|
if (calendarNames == null) {
|
||||||
|
LOG.info("Set null apps_notification_blacklist");
|
||||||
|
calendars_blacklist = new HashSet<>();
|
||||||
|
} else {
|
||||||
|
calendars_blacklist = new HashSet<>(calendarNames);
|
||||||
|
}
|
||||||
|
LOG.info("New calendars_blacklist has {} entries", calendars_blacklist.size());
|
||||||
|
saveCalendarsBlackList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCalendarToBlacklist(String calendarUniqueName) {
|
||||||
|
if (calendars_blacklist.add(calendarUniqueName)) {
|
||||||
|
LOG.info("Blacklisted calendar " + calendarUniqueName);
|
||||||
|
saveCalendarsBlackList();
|
||||||
|
} else {
|
||||||
|
LOG.warn("Calendar {} already blacklisted!", calendarUniqueName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFromCalendarBlacklist(String calendarUniqueName) {
|
||||||
|
calendars_blacklist.remove(calendarUniqueName);
|
||||||
|
LOG.info("Unblacklisted calendar " + calendarUniqueName);
|
||||||
|
saveCalendarsBlackList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadCalendarsBlackList() {
|
||||||
|
SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(deviceAddress);
|
||||||
|
|
||||||
|
LOG.info("Loading calendars_blacklist");
|
||||||
|
calendars_blacklist = (HashSet<String>) sharedPrefs.getStringSet(GBPrefs.CALENDAR_BLACKLIST, null);
|
||||||
|
if (calendars_blacklist == null) {
|
||||||
|
calendars_blacklist = new HashSet<>();
|
||||||
|
}
|
||||||
|
LOG.info("Loaded calendars_blacklist has {} entries", calendars_blacklist.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveCalendarsBlackList() {
|
||||||
|
final SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(deviceAddress);
|
||||||
|
|
||||||
|
LOG.info("Saving calendars_blacklist with {} entries", calendars_blacklist.size());
|
||||||
|
SharedPreferences.Editor editor = sharedPrefs.edit();
|
||||||
|
if (calendars_blacklist.isEmpty()) {
|
||||||
|
editor.putStringSet(GBPrefs.CALENDAR_BLACKLIST, null);
|
||||||
|
} else {
|
||||||
|
Prefs.putStringSet(editor, GBPrefs.CALENDAR_BLACKLIST, calendars_blacklist);
|
||||||
|
}
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
}
|
@ -205,6 +205,7 @@
|
|||||||
<string name="pref_title_weather_summary">Used for the LineageOS weather provider, other Android versions need to use an app like \"Weather notification\". Find more information in the Gadgetbridge wiki.</string>
|
<string name="pref_title_weather_summary">Used for the LineageOS weather provider, other Android versions need to use an app like \"Weather notification\". Find more information in the Gadgetbridge wiki.</string>
|
||||||
<string name="pref_applications_settings">Applications list</string>
|
<string name="pref_applications_settings">Applications list</string>
|
||||||
<string name="pref_blacklist_calendars">Blacklist Calendars</string>
|
<string name="pref_blacklist_calendars">Blacklist Calendars</string>
|
||||||
|
<string name="pref_blacklist_calendars_summary">Blacklisted calendars will not be synced to the device</string>
|
||||||
<string name="pref_header_cannned_messages">Canned messages</string>
|
<string name="pref_header_cannned_messages">Canned messages</string>
|
||||||
<string name="pref_title_canned_replies">Replies</string>
|
<string name="pref_title_canned_replies">Replies</string>
|
||||||
<string name="pref_title_canned_reply_suffix">Common suffix</string>
|
<string name="pref_title_canned_reply_suffix">Common suffix</string>
|
||||||
|
@ -6,4 +6,10 @@
|
|||||||
android:key="sync_calendar"
|
android:key="sync_calendar"
|
||||||
android:summary="@string/pref_summary_sync_calendar"
|
android:summary="@string/pref_summary_sync_calendar"
|
||||||
android:title="@string/pref_title_sync_caldendar" />
|
android:title="@string/pref_title_sync_caldendar" />
|
||||||
|
<Preference
|
||||||
|
android:dependency="sync_calendar"
|
||||||
|
android:icon="@drawable/ic_block"
|
||||||
|
android:key="blacklist_calendars"
|
||||||
|
android:summary="@string/pref_blacklist_calendars_summary"
|
||||||
|
android:title="@string/pref_blacklist_calendars" />
|
||||||
</androidx.preference.PreferenceScreen>
|
</androidx.preference.PreferenceScreen>
|
||||||
|
@ -194,15 +194,6 @@
|
|||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory android:title="@string/pref_header_pebble_timeline">
|
<PreferenceCategory android:title="@string/pref_header_pebble_timeline">
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:layout="@layout/preference_checkbox"
|
|
||||||
android:defaultValue="true"
|
|
||||||
android:key="enable_calendar_sync"
|
|
||||||
android:summary="@string/pref_summary_enable_calendar_sync"
|
|
||||||
android:title="@string/pref_title_enable_calendar_sync" />
|
|
||||||
<Preference
|
|
||||||
android:key="pref_key_blacklist_calendars"
|
|
||||||
android:title="@string/pref_blacklist_calendars" />
|
|
||||||
<CheckBoxPreference
|
|
||||||
android:layout="@layout/preference_checkbox"
|
android:layout="@layout/preference_checkbox"
|
||||||
android:key="send_sunrise_sunset"
|
android:key="send_sunrise_sunset"
|
||||||
android:summary="@string/pref_summary_sunrise_sunset"
|
android:summary="@string/pref_summary_sunrise_sunset"
|
||||||
|
@ -8,7 +8,7 @@ import java.util.List;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.entities.CalendarSyncStateDao;
|
import nodomain.freeyourgadget.gadgetbridge.entities.CalendarSyncStateDao;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.externalevents.CalendarReceiver;
|
import nodomain.freeyourgadget.gadgetbridge.externalevents.CalendarReceiver;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEvents;
|
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarEvent;
|
||||||
|
|
||||||
import static junit.framework.Assert.assertEquals;
|
import static junit.framework.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotEquals;
|
import static org.junit.Assert.assertNotEquals;
|
||||||
@ -24,12 +24,12 @@ public class CalendarEventTest extends TestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHashCode() {
|
public void testHashCode() {
|
||||||
CalendarEvents.CalendarEvent c1 =
|
CalendarEvent c1 =
|
||||||
new CalendarEvents.CalendarEvent(BEGIN, END, ID_1, "something", null, null, CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false);
|
new CalendarEvent(BEGIN, END, ID_1, "something", null, null, CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false);
|
||||||
CalendarEvents.CalendarEvent c2 =
|
CalendarEvent c2 =
|
||||||
new CalendarEvents.CalendarEvent(BEGIN, END, ID_1, null, "something", null, CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false);
|
new CalendarEvent(BEGIN, END, ID_1, null, "something", null, CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false);
|
||||||
CalendarEvents.CalendarEvent c3 =
|
CalendarEvent c3 =
|
||||||
new CalendarEvents.CalendarEvent(BEGIN, END, ID_1, null, null, "something", CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false);
|
new CalendarEvent(BEGIN, END, ID_1, null, null, "something", CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false);
|
||||||
|
|
||||||
assertEquals(c1.hashCode(), c1.hashCode());
|
assertEquals(c1.hashCode(), c1.hashCode());
|
||||||
assertNotEquals(c1.hashCode(), c2.hashCode());
|
assertNotEquals(c1.hashCode(), c2.hashCode());
|
||||||
@ -39,8 +39,8 @@ public class CalendarEventTest extends TestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSync() {
|
public void testSync() {
|
||||||
List<CalendarEvents.CalendarEvent> eventList = new ArrayList<>();
|
List<CalendarEvent> eventList = new ArrayList<>();
|
||||||
eventList.add(new CalendarEvents.CalendarEvent(BEGIN, END, ID_1, null, "something", null, CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false));
|
eventList.add(new CalendarEvent(BEGIN, END, ID_1, null, "something", null, CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false));
|
||||||
|
|
||||||
GBDevice dummyGBDevice = createDummyGDevice("00:00:01:00:03");
|
GBDevice dummyGBDevice = createDummyGDevice("00:00:01:00:03");
|
||||||
dummyGBDevice.setState(GBDevice.State.INITIALIZED);
|
dummyGBDevice.setState(GBDevice.State.INITIALIZED);
|
||||||
@ -49,7 +49,7 @@ public class CalendarEventTest extends TestBase {
|
|||||||
|
|
||||||
testCR.syncCalendar(eventList);
|
testCR.syncCalendar(eventList);
|
||||||
|
|
||||||
eventList.add(new CalendarEvents.CalendarEvent(BEGIN, END, ID_2, null, "something", null, CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false));
|
eventList.add(new CalendarEvent(BEGIN, END, ID_2, null, "something", null, CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false));
|
||||||
testCR.syncCalendar(eventList);
|
testCR.syncCalendar(eventList);
|
||||||
|
|
||||||
CalendarSyncStateDao calendarSyncStateDao = daoSession.getCalendarSyncStateDao();
|
CalendarSyncStateDao calendarSyncStateDao = daoSession.getCalendarSyncStateDao();
|
||||||
|
Loading…
Reference in New Issue
Block a user