mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Calendar Sync: Add the option to filter events
This change adds filter filters to the calendar sync options: 1. Declined events 2. Canceled events 3. Color Label filtering 4. Focus Time event filtering 5. Working Location event filtering 6. All Day Event filtering This changes also inverts the menu for teh sync black list so that is now a white list. The underlying prefs variables have not changed, just how the interface displays them so existing user settings will carry over. The color label filtering is more useful on calendars from Google Workspace Calendars that actually have named colors. There is no way that I can find to access the names of the colors to show to the user, but it can still be useful to tag some events that you don't want synced. In addition to the color filters, Google Workspace Calendar has extended parameters called Focus Time and Working Location. Working location appears as an all day event every day and if you use the Focus Time as a Calendar block, your calendar may be filled with these events. For my work calendar these two event types choke out the "real" events, so it is nice to filter them.
This commit is contained in:
@@ -287,8 +287,8 @@
|
||||
android:label="@string/title_activity_notification_management"
|
||||
android:parentActivityName=".activities.SettingsActivity" />
|
||||
<activity
|
||||
android:name=".activities.CalBlacklistActivity"
|
||||
android:label="@string/title_activity_calblacklist"
|
||||
android:name=".activities.CalendarSelectionActivity"
|
||||
android:label="@string/pref_title_calendar_sync_choose"
|
||||
android:parentActivityName=".activities.SettingsActivity" />
|
||||
<activity
|
||||
android:name=".devices.vesc.VescControlActivity"
|
||||
|
||||
-171
@@ -1,171 +0,0 @@
|
||||
/* Copyright (C) 2017-2024 Carsten Pfeiffer, Daniele Gobbetti, José Rebelo,
|
||||
Ludovic Jozeau
|
||||
|
||||
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 <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Paint;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.CalendarContract;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.app.NavUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarManager;
|
||||
|
||||
|
||||
public class CalBlacklistActivity extends AbstractGBActivity {
|
||||
|
||||
private final String[] EVENT_PROJECTION = new String[]{
|
||||
CalendarContract.Calendars.CALENDAR_DISPLAY_NAME,
|
||||
CalendarContract.Calendars.ACCOUNT_NAME,
|
||||
CalendarContract.Calendars.CALENDAR_COLOR
|
||||
};
|
||||
private ArrayList<Calendar> calendarsArrayList;
|
||||
|
||||
private GBDevice gbDevice;
|
||||
private CalendarManager calendarManager;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_calblacklist);
|
||||
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;
|
||||
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);
|
||||
return;
|
||||
}
|
||||
try (Cursor cur = getContentResolver().query(uri, EVENT_PROJECTION, null, null, null)) {
|
||||
calendarsArrayList = new ArrayList<>();
|
||||
while (cur != null && cur.moveToNext()) {
|
||||
calendarsArrayList.add(new Calendar(cur.getString(0), cur.getString(1), cur.getInt(2)));
|
||||
}
|
||||
}
|
||||
|
||||
ArrayAdapter<Calendar> calAdapter = new CalendarListAdapter(this, calendarsArrayList);
|
||||
calListView.setAdapter(calAdapter);
|
||||
calListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int i, long id) {
|
||||
Calendar item = calendarsArrayList.get(i);
|
||||
CheckBox selected = (CheckBox) view.findViewById(R.id.item_checkbox);
|
||||
toggleEntry(view);
|
||||
if (selected.isChecked()) {
|
||||
calendarManager.addCalendarToBlacklist(item.getUniqueString());
|
||||
} else {
|
||||
calendarManager.removeFromCalendarBlacklist(item.getUniqueString());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
final int itemId = item.getItemId();
|
||||
if (itemId == android.R.id.home) {
|
||||
NavUtils.navigateUpFromSameTask(this);
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void toggleEntry(View view) {
|
||||
TextView name = (TextView) view.findViewById(R.id.calendar_name);
|
||||
CheckBox checked = (CheckBox) view.findViewById(R.id.item_checkbox);
|
||||
|
||||
name.setPaintFlags(name.getPaintFlags() ^ Paint.STRIKE_THRU_TEXT_FLAG);
|
||||
checked.toggle();
|
||||
}
|
||||
|
||||
class Calendar {
|
||||
private final String displayName;
|
||||
private final String accountName;
|
||||
private final int color;
|
||||
|
||||
public Calendar(String displayName, String accountName, int color) {
|
||||
this.displayName = displayName;
|
||||
this.accountName = accountName;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public String getUniqueString() {
|
||||
return accountName + '/' + displayName;
|
||||
}
|
||||
}
|
||||
|
||||
private class CalendarListAdapter extends ArrayAdapter<Calendar> {
|
||||
|
||||
CalendarListAdapter(@NonNull Context context, @NonNull List<Calendar> calendars) {
|
||||
super(context, 0, calendars);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, @Nullable View view, @NonNull ViewGroup parent) {
|
||||
Calendar item = getItem(position);
|
||||
|
||||
if (view == null) {
|
||||
LayoutInflater inflater = (LayoutInflater) super.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
view = inflater.inflate(R.layout.item_cal_blacklist, parent, false);
|
||||
}
|
||||
|
||||
View color = view.findViewById(R.id.calendar_color);
|
||||
TextView name = (TextView) view.findViewById(R.id.calendar_name);
|
||||
TextView ownerAccount = (TextView) view.findViewById(R.id.calendar_owner_account);
|
||||
CheckBox checked = (CheckBox) view.findViewById(R.id.item_checkbox);
|
||||
|
||||
if (calendarManager.calendarIsBlacklisted(item.getUniqueString()) && !checked.isChecked() ||
|
||||
!calendarManager.calendarIsBlacklisted(item.getUniqueString()) && checked.isChecked()) {
|
||||
toggleEntry(view);
|
||||
}
|
||||
color.setBackgroundColor(item.color);
|
||||
name.setText(item.displayName);
|
||||
ownerAccount.setText(item.accountName);
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
/* Copyright (C) 2017-2024 Carsten Pfeiffer, Daniele Gobbetti, José Rebelo,
|
||||
Ludovic Jozeau
|
||||
|
||||
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 <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.app.NavUtils;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarManager;
|
||||
|
||||
|
||||
public class CalendarSelectionActivity extends AbstractGBActivity {
|
||||
private GBDevice gbDevice;
|
||||
private CalendarManager calendarManager;
|
||||
private List<CalendarManager.CalendarEntry> calendars;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_calendar_selection);
|
||||
ListView calListView = (ListView) findViewById(R.id.calendar_selection_list_view);
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
gbDevice = getIntent().getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||
calendarManager = new CalendarManager(this, gbDevice.getAddress());
|
||||
calendars = calendarManager.getCalendars();
|
||||
|
||||
CalendarListAdapter calAdapter = new CalendarListAdapter(this, calendarManager, calendars);
|
||||
calListView.setAdapter(calAdapter);
|
||||
calListView.setOnItemClickListener(calAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
final int itemId = item.getItemId();
|
||||
if (itemId == android.R.id.home) {
|
||||
NavUtils.navigateUpFromSameTask(this);
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private class CalendarListAdapter extends ArrayAdapter<CalendarManager.CalendarEntry>
|
||||
implements AdapterView.OnItemClickListener {
|
||||
private final CalendarManager calendarManager;
|
||||
|
||||
CalendarListAdapter(@NonNull Context context, CalendarManager calendarManager,
|
||||
@NonNull List<CalendarManager.CalendarEntry> calendars) {
|
||||
super(context, 0, calendars);
|
||||
this.calendarManager = calendarManager;
|
||||
}
|
||||
|
||||
private void setRowStyle(View view, boolean enabled) {
|
||||
// Set the state of the checkbox.
|
||||
CheckBox checked = (CheckBox) view.findViewById(R.id.item_checkbox);
|
||||
checked.setChecked(enabled);
|
||||
|
||||
// Make the color slightly transparent when disabled.
|
||||
View colorBox = view.findViewById(R.id.calendar_color);
|
||||
Drawable background = colorBox.getBackground();
|
||||
background.setAlpha(enabled ? 0xFF : 0x2F);
|
||||
colorBox.setBackground(background);
|
||||
|
||||
// Grey out the text if not enabled.
|
||||
view.findViewById(R.id.calendar_name).setEnabled(enabled);
|
||||
view.findViewById(R.id.calendar_owner_account).setEnabled(enabled);
|
||||
|
||||
// If the color selection button is enabled, make it visible if the row is also enabled.
|
||||
ImageView colorButton = (ImageView) view.findViewById(R.id.calendar_color_drop_down);
|
||||
colorButton.setVisibility(
|
||||
(enabled && colorButton.isEnabled()) ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, @Nullable View view, @NonNull ViewGroup parent) {
|
||||
CalendarManager.CalendarEntry item = getItem(position);
|
||||
|
||||
if (view == null) {
|
||||
LayoutInflater inflater = (LayoutInflater) super.getContext().getSystemService(
|
||||
Context.LAYOUT_INFLATER_SERVICE);
|
||||
view = inflater.inflate(R.layout.item_calendar_selection, parent, false);
|
||||
}
|
||||
|
||||
// Populate each element
|
||||
((TextView) view.findViewById(R.id.calendar_name)).setText(item.displayName());
|
||||
((TextView) view.findViewById(R.id.calendar_owner_account)).setText(item.accountName());
|
||||
view.findViewById(R.id.calendar_color).setBackgroundColor(item.color());
|
||||
View colorDropDown = view.findViewById(R.id.calendar_color_drop_down);
|
||||
colorDropDown.setEnabled(!item.eventColors().isEmpty());
|
||||
|
||||
if (!item.eventColors().isEmpty()) {
|
||||
colorDropDown.setOnClickListener((button) -> {
|
||||
// Create a new layout for the dialog
|
||||
LayoutInflater inflater =
|
||||
(LayoutInflater) super.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
View colorView =
|
||||
inflater.inflate(R.layout.activity_calendar_color_selection, null);
|
||||
|
||||
GridView colorListView =
|
||||
(GridView) colorView.findViewById(R.id.calendar_color_selection_list_view);
|
||||
|
||||
CalendarColorGridAdapter colorAdaptor =
|
||||
new CalendarColorGridAdapter(super.getContext(), calendarManager,
|
||||
item.getUniqueString(), item.eventColors().stream().sorted().toList());
|
||||
colorListView.setAdapter(colorAdaptor);
|
||||
colorListView.setOnItemClickListener(colorAdaptor);
|
||||
|
||||
new MaterialAlertDialogBuilder(getContext())
|
||||
.setTitle(R.string.pref_title_calendar_sync_colors)
|
||||
.setView(colorView).setIcon(R.drawable.ic_calendar_cancel)
|
||||
.setPositiveButton(R.string.done, null)
|
||||
.show();
|
||||
});
|
||||
}
|
||||
|
||||
setRowStyle(view, !calendarManager.isCalendarBlacklisted(item.getUniqueString()));
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
CalendarManager.CalendarEntry item = getItem(position);
|
||||
// Invert the checkbox on click before checking it's state below.
|
||||
CheckBox selected = (CheckBox) view.findViewById(R.id.item_checkbox);
|
||||
selected.toggle();
|
||||
|
||||
setRowStyle(view, selected.isChecked());
|
||||
|
||||
if (selected.isChecked()) {
|
||||
calendarManager.removeFromCalendarBlacklist(item.getUniqueString());
|
||||
} else {
|
||||
calendarManager.addCalendarToBlacklist(item.getUniqueString());
|
||||
}
|
||||
|
||||
GBApplication.deviceService(gbDevice).onSendConfiguration(GBPrefs.CALENDAR_BLACKLIST);
|
||||
}
|
||||
}
|
||||
|
||||
private class CalendarColorGridAdapter extends ArrayAdapter<Integer>
|
||||
implements AdapterView.OnItemClickListener {
|
||||
private final CalendarManager calendarManager;
|
||||
private final String calendarUniqueName;
|
||||
|
||||
CalendarColorGridAdapter(@NonNull Context context, @NonNull CalendarManager calendarManager,
|
||||
@NonNull String calendarUniqueName,
|
||||
@NonNull List<Integer> colors) {
|
||||
super(context, 0, colors);
|
||||
this.calendarManager = calendarManager;
|
||||
this.calendarUniqueName = calendarUniqueName;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, @Nullable View view, @NonNull ViewGroup parent) {
|
||||
int color = getItem(position);
|
||||
|
||||
if (view == null) {
|
||||
LayoutInflater inflater = (LayoutInflater) super.getContext().getSystemService(
|
||||
Context.LAYOUT_INFLATER_SERVICE);
|
||||
view = inflater.inflate(R.layout.item_calendar_color_selection, parent, false);
|
||||
}
|
||||
CheckBox checked = (CheckBox) view.findViewById(R.id.item_event_color);
|
||||
checked.setChecked(!calendarManager.isColorBlacklistedForCalendar(calendarUniqueName, color));
|
||||
checked.setButtonTintList(ColorStateList.valueOf(0xFF000000 | color));
|
||||
checked.setBackgroundColor(0xFF000000 | color);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
int color = getItem(position);
|
||||
// Invert the checkbox on click before checking it's state below.
|
||||
CheckBox selected = (CheckBox) view.findViewById(R.id.item_event_color);
|
||||
selected.toggle();
|
||||
if (selected.isChecked()) {
|
||||
calendarManager.removeColorFromBlacklistForCalendar(calendarUniqueName, color);
|
||||
} else {
|
||||
calendarManager.addColorToBlacklistForCalendar(calendarUniqueName, color);
|
||||
}
|
||||
GBApplication.deviceService(gbDevice).onSendConfiguration(
|
||||
DeviceSettingsPreferenceConst.PREF_CALENDAR_SYNC_COLOR_BLACKLIST);
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -89,6 +89,12 @@ public class DeviceSettingsPreferenceConst {
|
||||
public static final String PREF_CALENDAR_MAX_TITLE_LENGTH = "calendar_sync_event_title_length";
|
||||
public static final String PREF_CALENDAR_MAX_DESC_LENGTH = "calendar_sync_event_desc_length";
|
||||
public static final String PREF_CALENDAR_TARGET_APP = "calendar_sync_target_app";
|
||||
public static final String PREF_CALENDAR_SYNC_CANCELED = "calendar_sync_canceled";
|
||||
public static final String PREF_CALENDAR_SYNC_DECLINED = "calendar_sync_declined";
|
||||
public static final String PREF_CALENDAR_SYNC_FOCUS_TIME = "calendar_sync_focus_time";
|
||||
public static final String PREF_CALENDAR_SYNC_ALL_DAY = "calendar_sync_all_day";
|
||||
public static final String PREF_CALENDAR_SYNC_WORKING_LOCATION = "calendar_sync_working_location";
|
||||
public static final String PREF_CALENDAR_SYNC_COLOR_BLACKLIST = "calendar_sync_color_blacklist";
|
||||
public static final String PREF_TIME_SYNC = "time_sync";
|
||||
public static final String PREF_WEIGHT_SCALE_UNIT = "pref_weight_scale_unit";
|
||||
public static final String PREF_USE_CUSTOM_DEVICEICON = "use_custom_deviceicon";
|
||||
|
||||
+13
-9
@@ -73,7 +73,7 @@ import nodomain.freeyourgadget.gadgetbridge.BuildConfig;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractPreferenceFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.CalBlacklistActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.CalendarSelectionActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureContacts;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureWorldClocks;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.NotificationsAppIconUploadActivity;
|
||||
@@ -93,6 +93,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.preferences.GBSimpleSummaryProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.preferences.MinMaxTextWatcher;
|
||||
@@ -1019,6 +1020,11 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
|
||||
addPreferenceHandlerFor(PREF_CALENDAR_MAX_TITLE_LENGTH);
|
||||
addPreferenceHandlerFor(PREF_CALENDAR_MAX_DESC_LENGTH);
|
||||
addPreferenceHandlerFor(PREF_CALENDAR_TARGET_APP);
|
||||
addPreferenceHandlerFor(PREF_CALENDAR_SYNC_CANCELED);
|
||||
addPreferenceHandlerFor(PREF_CALENDAR_SYNC_DECLINED);
|
||||
addPreferenceHandlerFor(PREF_CALENDAR_SYNC_FOCUS_TIME);
|
||||
addPreferenceHandlerFor(PREF_CALENDAR_SYNC_ALL_DAY);
|
||||
addPreferenceHandlerFor(PREF_CALENDAR_SYNC_WORKING_LOCATION);
|
||||
|
||||
addPreferenceHandlerFor(PREF_ATC_BLE_OEPL_MODEL);
|
||||
addPreferenceHandlerFor(PREF_ATC_BLE_OEPL_BLE_ADV_INTERVAL);
|
||||
@@ -1274,15 +1280,13 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
|
||||
});
|
||||
}
|
||||
|
||||
final Preference calendarBlacklist = findPreference("blacklist_calendars");
|
||||
final Preference calendarBlacklist = findPreference(GBPrefs.CALENDAR_BLACKLIST);
|
||||
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;
|
||||
}
|
||||
calendarBlacklist.setOnPreferenceClickListener(preference -> {
|
||||
Intent intent = new Intent(getContext(), CalendarSelectionActivity.class);
|
||||
intent.putExtra(GBDevice.EXTRA_DEVICE, device);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -39,9 +39,9 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import de.greenrobot.dao.query.QueryBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.BuildConfig;
|
||||
@@ -53,9 +53,9 @@ import nodomain.freeyourgadget.gadgetbridge.entities.CalendarSyncStateDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarEvent;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarManager;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
public class CalendarReceiver extends ContentObserver {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CalendarReceiver.class);
|
||||
@@ -253,7 +253,9 @@ public class CalendarReceiver extends ContentObserver {
|
||||
calendarEventSpec.location = calendarEvent.getLocation();
|
||||
calendarEventSpec.type = CalendarEventSpec.TYPE_UNKNOWN;
|
||||
calendarEventSpec.calName = calendarEvent.getUniqueCalName();
|
||||
calendarEventSpec.calendarColor = calendarEvent.getCalendarColor();
|
||||
calendarEventSpec.color = calendarEvent.getColor();
|
||||
calendarEventSpec.attendingStatus = calendarEvent.getAttendingStatus();
|
||||
if (syncState == EventState.NEEDS_UPDATE) {
|
||||
GBApplication.deviceService(mGBDevice).onDeleteCalendarEvent(CalendarEventSpec.TYPE_UNKNOWN, i);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.impl;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.util.JavaExtensions.coalesce;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -29,6 +31,11 @@ import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.ContactsContract;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -51,13 +58,6 @@ import nodomain.freeyourgadget.gadgetbridge.model.WorldClock;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.RtlUtils;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.util.JavaExtensions.coalesce;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
public class GBDeviceService implements DeviceService {
|
||||
protected final Context mContext;
|
||||
@@ -456,6 +456,7 @@ public class GBDeviceService implements DeviceService {
|
||||
public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) {
|
||||
Intent intent = createIntent().setAction(ACTION_ADD_CALENDAREVENT)
|
||||
.putExtra(EXTRA_CALENDAREVENT_ID, calendarEventSpec.id)
|
||||
.putExtra(EXTRA_CALENDAREVENT_EVENT_ID, calendarEventSpec.eventId)
|
||||
.putExtra(EXTRA_CALENDAREVENT_TYPE, calendarEventSpec.type)
|
||||
.putExtra(EXTRA_CALENDAREVENT_TIMESTAMP, calendarEventSpec.timestamp)
|
||||
.putExtra(EXTRA_CALENDAREVENT_DURATION, calendarEventSpec.durationInSeconds)
|
||||
@@ -464,8 +465,11 @@ public class GBDeviceService implements DeviceService {
|
||||
.putExtra(EXTRA_CALENDAREVENT_TITLE, calendarEventSpec.title)
|
||||
.putExtra(EXTRA_CALENDAREVENT_DESCRIPTION, calendarEventSpec.description)
|
||||
.putExtra(EXTRA_CALENDAREVENT_CALNAME, calendarEventSpec.calName)
|
||||
.putExtra(EXTRA_CALENDAREVENT_CALENDAR_COLOR, calendarEventSpec.calendarColor)
|
||||
.putExtra(EXTRA_CALENDAREVENT_COLOR, calendarEventSpec.color)
|
||||
.putExtra(EXTRA_CALENDAREVENT_LOCATION, calendarEventSpec.location);
|
||||
.putExtra(EXTRA_CALENDAREVENT_LOCATION, calendarEventSpec.location)
|
||||
.putExtra(EXTRA_CALENDAREVENT_STATUS, calendarEventSpec.location)
|
||||
.putExtra(EXTRA_CALENDAREVENT_ATTENDING_STATUS, calendarEventSpec.location);
|
||||
invokeService(intent);
|
||||
}
|
||||
|
||||
@@ -473,6 +477,7 @@ public class GBDeviceService implements DeviceService {
|
||||
public void onDeleteCalendarEvent(byte type, long id) {
|
||||
Intent intent = createIntent().setAction(ACTION_DELETE_CALENDAREVENT)
|
||||
.putExtra(EXTRA_CALENDAREVENT_TYPE, type)
|
||||
// TODO: If swapping to EVENT_ID, change this here.
|
||||
.putExtra(EXTRA_CALENDAREVENT_ID, id);
|
||||
invokeService(intent);
|
||||
}
|
||||
|
||||
@@ -26,13 +26,17 @@ public class CalendarEventSpec {
|
||||
|
||||
public byte type;
|
||||
public long id;
|
||||
public long eventId;
|
||||
public int timestamp;
|
||||
public int durationInSeconds;
|
||||
public String title;
|
||||
public String description;
|
||||
public String location;
|
||||
public String calName;
|
||||
public int calendarColor;
|
||||
public int color;
|
||||
public boolean allDay;
|
||||
public ArrayList<Long> reminders; // unix epoch millis
|
||||
public int status;
|
||||
public int attendingStatus;
|
||||
}
|
||||
|
||||
@@ -164,6 +164,7 @@ public interface DeviceService extends EventHandler {
|
||||
@Deprecated
|
||||
String EXTRA_HEART_RATE_VALUE = "hr_value";
|
||||
String EXTRA_CALENDAREVENT_ID = "calendarevent_id";
|
||||
String EXTRA_CALENDAREVENT_EVENT_ID = "calendarevent_event_id";
|
||||
String EXTRA_CALENDAREVENT_TYPE = "calendarevent_type";
|
||||
String EXTRA_CALENDAREVENT_TIMESTAMP = "calendarevent_timestamp";
|
||||
String EXTRA_CALENDAREVENT_DURATION = "calendarevent_duration";
|
||||
@@ -173,7 +174,10 @@ public interface DeviceService extends EventHandler {
|
||||
String EXTRA_CALENDAREVENT_DESCRIPTION = "calendarevent_description";
|
||||
String EXTRA_CALENDAREVENT_LOCATION = "calendarevent_location";
|
||||
String EXTRA_CALENDAREVENT_CALNAME = "calendarevent_calname";
|
||||
String EXTRA_CALENDAREVENT_CALENDAR_COLOR = "calendarevent_calendar_color";
|
||||
String EXTRA_CALENDAREVENT_COLOR = "calendarevent_color";
|
||||
String EXTRA_CALENDAREVENT_STATUS = "calendarevent_status";
|
||||
String EXTRA_CALENDAREVENT_ATTENDING_STATUS = "calendarevent_attending_status";
|
||||
|
||||
void connect();
|
||||
|
||||
|
||||
+7
-1
@@ -47,10 +47,10 @@ import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Contact;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NavigationInfoSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WorldClock;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NavigationInfoSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.weather.Weather;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.preferences.DevicePrefs;
|
||||
|
||||
@@ -554,6 +554,12 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
|
||||
switch (config) {
|
||||
case DeviceSettingsPreferenceConst.PREF_SYNC_CALENDAR:
|
||||
case DeviceSettingsPreferenceConst.PREF_SYNC_BIRTHDAYS:
|
||||
case DeviceSettingsPreferenceConst.PREF_CALENDAR_SYNC_CANCELED:
|
||||
case DeviceSettingsPreferenceConst.PREF_CALENDAR_SYNC_DECLINED:
|
||||
case DeviceSettingsPreferenceConst.PREF_CALENDAR_SYNC_FOCUS_TIME:
|
||||
case DeviceSettingsPreferenceConst.PREF_CALENDAR_SYNC_ALL_DAY:
|
||||
case DeviceSettingsPreferenceConst.PREF_CALENDAR_SYNC_WORKING_LOCATION:
|
||||
case DeviceSettingsPreferenceConst.PREF_CALENDAR_SYNC_COLOR_BLACKLIST:
|
||||
CalendarReceiver.forceSync(getDevice());
|
||||
break;
|
||||
}
|
||||
|
||||
+9
-5
@@ -23,6 +23,11 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_STRESS_TEST_CONNECT_COUNT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_STRESS_TEST_CONNECT_PARALLEL;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_STRESS_TEST_DISPOSE;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.*;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActivityManager;
|
||||
@@ -118,11 +123,6 @@ import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.language.LanguageUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.language.Transliterator;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_STRESS_TEST_CONNECT_COUNT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_STRESS_TEST_CONNECT_PARALLEL;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_STRESS_TEST_DISPOSE;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.*;
|
||||
|
||||
public class DeviceCommunicationService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
public static class DeviceStruct{
|
||||
private GBDevice device;
|
||||
@@ -969,6 +969,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
||||
case ACTION_ADD_CALENDAREVENT: {
|
||||
CalendarEventSpec calendarEventSpec = new CalendarEventSpec();
|
||||
calendarEventSpec.id = intentCopy.getLongExtra(EXTRA_CALENDAREVENT_ID, -1);
|
||||
calendarEventSpec.eventId = intentCopy.getLongExtra(EXTRA_CALENDAREVENT_ID, -1);
|
||||
calendarEventSpec.type = intentCopy.getByteExtra(EXTRA_CALENDAREVENT_TYPE, (byte) -1);
|
||||
calendarEventSpec.timestamp = intentCopy.getIntExtra(EXTRA_CALENDAREVENT_TIMESTAMP, -1);
|
||||
calendarEventSpec.durationInSeconds = intentCopy.getIntExtra(EXTRA_CALENDAREVENT_DURATION, -1);
|
||||
@@ -978,7 +979,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
||||
calendarEventSpec.description = intentCopy.getStringExtra(EXTRA_CALENDAREVENT_DESCRIPTION);
|
||||
calendarEventSpec.location = intentCopy.getStringExtra(EXTRA_CALENDAREVENT_LOCATION);
|
||||
calendarEventSpec.calName = intentCopy.getStringExtra(EXTRA_CALENDAREVENT_CALNAME);
|
||||
calendarEventSpec.calendarColor = intentCopy.getIntExtra(EXTRA_CALENDAREVENT_CALENDAR_COLOR, 0);
|
||||
calendarEventSpec.color = intentCopy.getIntExtra(EXTRA_CALENDAREVENT_COLOR, 0);
|
||||
calendarEventSpec.status = intentCopy.getIntExtra(EXTRA_CALENDAREVENT_STATUS, 0);
|
||||
calendarEventSpec.attendingStatus = intentCopy.getIntExtra(EXTRA_CALENDAREVENT_ATTENDING_STATUS, 0);
|
||||
deviceSupport.onAddCalendarEvent(calendarEventSpec);
|
||||
break;
|
||||
}
|
||||
|
||||
+2
-2
@@ -62,7 +62,7 @@ public class HuaweiP2PCalendarService extends HuaweiBaseP2PService {
|
||||
public final int OPERATION_ADD = 1;
|
||||
public final int OPERATION_DELETE = 2;
|
||||
public final int OPERATION_UPDATE = 3;
|
||||
|
||||
|
||||
public static final String MODULE = "hw.unitedevice.calendarapp";
|
||||
|
||||
private final AtomicBoolean isRegistered = new AtomicBoolean(false);
|
||||
@@ -206,7 +206,7 @@ public class HuaweiP2PCalendarService extends HuaweiBaseP2PService {
|
||||
ret.addProperty("account_name", truncateToHexBytes(calendarEvent.getCalAccountName(), 64));
|
||||
ret.addProperty("account_type", truncateToHexBytes(calendarEvent.getCalAccountType(), 64));
|
||||
ret.addProperty("all_day", calendarEvent.isAllDay() ? 1 : 0);
|
||||
ret.addProperty("calendar_color", calendarEvent.getColor());
|
||||
ret.addProperty("calendar_color", calendarEvent.getCalendarColor());
|
||||
ret.addProperty("calendar_displayName", truncateToHexBytes(calendarEvent.getCalName(), 64));
|
||||
ret.addProperty("calendar_id", valueOrEmpty(calendarEvent.getCalendarId(), "0"));
|
||||
ret.addProperty("description", truncateToHexBytes(calendarEvent.getDescription(), 512));
|
||||
|
||||
+36
-8
@@ -24,6 +24,7 @@ public class CalendarEvent {
|
||||
private final long begin;
|
||||
private final long end;
|
||||
private final long id;
|
||||
private final long eventId;
|
||||
private final String title;
|
||||
private final String description;
|
||||
private final String location;
|
||||
@@ -32,30 +33,36 @@ public class CalendarEvent {
|
||||
private final String calAccountType;
|
||||
private final String calendarId;
|
||||
private final String organizer;
|
||||
private final int calendarColor;
|
||||
private final int color;
|
||||
private final boolean allDay;
|
||||
private final String rrule;
|
||||
private final int status;
|
||||
private final int attendingStatus;
|
||||
private List<Long> remindersAbsoluteTs = new ArrayList<>();
|
||||
|
||||
public CalendarEvent(long begin, long end, long id, String title, String description, String location, String calName, String calAccountName, int color, boolean allDay, String organizer, String calAccountType, String calendarId, String rrule) {
|
||||
public CalendarEvent(long begin, long end, long id, long eventId, String title, String description,
|
||||
String location, String calName, String calAccountName, int calendarColor,
|
||||
int color, boolean allDay, String organizer, String calAccountType,
|
||||
String calendarId, String rrule, int status, int attendingStatus) {
|
||||
this.begin = begin;
|
||||
this.end = end;
|
||||
this.id = id;
|
||||
this.eventId = eventId;
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.location = location;
|
||||
this.calName = calName;
|
||||
this.calAccountName = calAccountName;
|
||||
this.calendarColor = calendarColor;
|
||||
this.color = color;
|
||||
this.allDay = allDay;
|
||||
this.organizer = organizer;
|
||||
this.calAccountType = calAccountType;
|
||||
this.calendarId = calendarId;
|
||||
this.rrule = rrule;
|
||||
}
|
||||
|
||||
public List<Long> getRemindersAbsoluteTs() {
|
||||
return remindersAbsoluteTs;
|
||||
this.status = status;
|
||||
this.attendingStatus = attendingStatus;
|
||||
}
|
||||
|
||||
public void setRemindersAbsoluteTs(List<Long> remindersAbsoluteTs) {
|
||||
@@ -95,6 +102,10 @@ public class CalendarEvent {
|
||||
return id;
|
||||
}
|
||||
|
||||
public long getEventId() {
|
||||
return eventId;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
@@ -123,6 +134,10 @@ public class CalendarEvent {
|
||||
return getCalAccountName() + '/' + getCalName();
|
||||
}
|
||||
|
||||
public int getCalendarColor() {
|
||||
return calendarColor;
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return color;
|
||||
}
|
||||
@@ -143,11 +158,17 @@ public class CalendarEvent {
|
||||
return rrule;
|
||||
}
|
||||
|
||||
public int getStatus() { return status; }
|
||||
|
||||
public List<Long> getRemindersAbsoluteTs() { return remindersAbsoluteTs; }
|
||||
|
||||
public int getAttendingStatus() { return attendingStatus; }
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof CalendarEvent) {
|
||||
CalendarEvent e = (CalendarEvent) other;
|
||||
if (other instanceof CalendarEvent e) {
|
||||
return (this.getId() == e.getId()) &&
|
||||
(this.getEventId() == e.getEventId()) &&
|
||||
Objects.equals(this.getTitle(), e.getTitle()) &&
|
||||
(this.getBegin() == e.getBegin()) &&
|
||||
Objects.equals(this.getLocation(), e.getLocation()) &&
|
||||
@@ -155,13 +176,16 @@ public class CalendarEvent {
|
||||
(this.getEnd() == e.getEnd()) &&
|
||||
Objects.equals(this.getCalName(), e.getCalName()) &&
|
||||
Objects.equals(this.getCalAccountName(), e.getCalAccountName()) &&
|
||||
(this.getCalendarColor() == e.getCalendarColor()) &&
|
||||
(this.getColor() == e.getColor()) &&
|
||||
(this.isAllDay() == e.isAllDay()) &&
|
||||
Objects.equals(this.getOrganizer(), e.getOrganizer()) &&
|
||||
Objects.equals(this.getRemindersAbsoluteTs(), e.getRemindersAbsoluteTs()) &&
|
||||
Objects.equals(this.getCalAccountType(), e.getCalAccountType()) &&
|
||||
Objects.equals(this.getCalendarId(), e.getCalendarId()) &&
|
||||
Objects.equals(this.getRrule(), e.getRrule());
|
||||
Objects.equals(this.getRrule(), e.getRrule()) &&
|
||||
Objects.equals(this.getStatus(), e.getStatus()) &&
|
||||
Objects.equals(this.getAttendingStatus(), e.getAttendingStatus());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -170,6 +194,7 @@ public class CalendarEvent {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (int) id;
|
||||
result = 31 * result + Objects.hash(eventId);
|
||||
result = 31 * result + Objects.hash(title);
|
||||
result = 31 * result + Long.valueOf(begin).hashCode();
|
||||
result = 31 * result + Objects.hash(location);
|
||||
@@ -177,6 +202,7 @@ public class CalendarEvent {
|
||||
result = 31 * result + Long.valueOf(end).hashCode();
|
||||
result = 31 * result + Objects.hash(calName);
|
||||
result = 31 * result + Objects.hash(calAccountName);
|
||||
result = 31 * result + Integer.valueOf(calendarColor).hashCode();
|
||||
result = 31 * result + Integer.valueOf(color).hashCode();
|
||||
result = 31 * result + Boolean.valueOf(allDay).hashCode();
|
||||
result = 31 * result + Objects.hash(organizer);
|
||||
@@ -184,6 +210,8 @@ public class CalendarEvent {
|
||||
result = 31 * result + Objects.hash(calAccountType);
|
||||
result = 31 * result + Objects.hash(calendarId);
|
||||
result = 31 * result + Objects.hash(rrule);
|
||||
result = 31 * result + Objects.hash(status);
|
||||
result = 31 * result + Objects.hash(attendingStatus);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
+262
-53
@@ -28,6 +28,9 @@ import android.text.format.Time;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -38,10 +41,14 @@ import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Comparator;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
@@ -61,34 +68,22 @@ public class CalendarManager {
|
||||
// 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.ORGANIZER,
|
||||
Instances.CALENDAR_DISPLAY_NAME,
|
||||
CalendarContract.Calendars.ACCOUNT_NAME,
|
||||
Instances.CALENDAR_COLOR,
|
||||
Instances.ALL_DAY,
|
||||
Instances.EVENT_ID, //needed for reminders
|
||||
CalendarContract.Calendars.ACCOUNT_TYPE,
|
||||
Instances.CALENDAR_ID,
|
||||
Instances.RRULE
|
||||
};
|
||||
|
||||
private final String deviceAddress;
|
||||
private final Context mContext;
|
||||
private HashSet<String> calendarBlacklist = null;
|
||||
private Map<String, HashSet<Integer>> colorBlacklist = null;
|
||||
|
||||
public record CalendarEntry(String displayName, String accountName, int color, Set<Integer> eventColors) {
|
||||
public String getUniqueString() {
|
||||
return accountName + '/' + displayName;
|
||||
}
|
||||
}
|
||||
|
||||
public CalendarManager(final Context context, final String deviceAddress) {
|
||||
this.mContext = context;
|
||||
this.deviceAddress = deviceAddress;
|
||||
|
||||
loadCalendarsBlackList();
|
||||
loadColorBlackList();
|
||||
}
|
||||
|
||||
public List<CalendarEvent> getCalendarEventList() {
|
||||
@@ -99,6 +94,7 @@ public class CalendarManager {
|
||||
|
||||
public List<CalendarEvent> getCalendarEventList(final int lookaheadDays) {
|
||||
loadCalendarsBlackList();
|
||||
loadColorBlackList();
|
||||
|
||||
final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(deviceAddress));
|
||||
|
||||
@@ -111,6 +107,7 @@ public class CalendarManager {
|
||||
calendarEventList.addAll(getBirthdays(lookaheadDays));
|
||||
calendarEventList.sort(Comparator.comparingInt(CalendarEvent::getBeginSeconds));
|
||||
}
|
||||
|
||||
return calendarEventList;
|
||||
}
|
||||
|
||||
@@ -127,7 +124,55 @@ public class CalendarManager {
|
||||
ContentUris.appendId(eventsUriBuilder, dtEnd);
|
||||
Uri eventsUri = eventsUriBuilder.build();
|
||||
|
||||
try (Cursor evtCursor = mContext.getContentResolver().query(eventsUri, EVENT_INSTANCE_PROJECTION, null, null, Instances.BEGIN + " ASC")) {
|
||||
final String[] EVENT_INSTANCE_PROJECTION = new String[]{
|
||||
Instances._ID,
|
||||
Instances.BEGIN,
|
||||
Instances.END,
|
||||
Instances.DURATION,
|
||||
Instances.TITLE,
|
||||
Instances.DESCRIPTION,
|
||||
Instances.EVENT_LOCATION,
|
||||
Instances.ORGANIZER,
|
||||
Instances.CALENDAR_DISPLAY_NAME,
|
||||
CalendarContract.Calendars.ACCOUNT_NAME,
|
||||
Instances.CALENDAR_COLOR,
|
||||
Instances.EVENT_COLOR,
|
||||
Instances.ALL_DAY,
|
||||
Instances.EVENT_ID, //needed for reminders
|
||||
CalendarContract.Calendars.ACCOUNT_TYPE,
|
||||
Instances.CALENDAR_ID,
|
||||
Instances.RRULE,
|
||||
Instances.STATUS,
|
||||
Instances.SELF_ATTENDEE_STATUS,
|
||||
Instances.HAS_EXTENDED_PROPERTIES
|
||||
};
|
||||
|
||||
final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(deviceAddress));
|
||||
boolean filterCanceled = !prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_CALENDAR_SYNC_CANCELED, true);
|
||||
boolean filterDeclined = !prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_CALENDAR_SYNC_DECLINED, true);
|
||||
boolean filterAllDay = !prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_CALENDAR_SYNC_ALL_DAY, true);
|
||||
|
||||
ArrayList<String> selectionArgsList = new ArrayList<>();
|
||||
StringJoiner selection = new StringJoiner(" AND ");
|
||||
if (filterCanceled) {
|
||||
selection.add(Instances.STATUS + " != ?");
|
||||
selectionArgsList.add(String.valueOf(CalendarContract.Instances.STATUS_CANCELED));
|
||||
}
|
||||
|
||||
if (filterDeclined) {
|
||||
selection.add(Instances.SELF_ATTENDEE_STATUS + " != ?");
|
||||
selectionArgsList.add(String.valueOf(CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED));
|
||||
}
|
||||
|
||||
if (filterAllDay) {
|
||||
selection.add(Instances.ALL_DAY + " != ?");
|
||||
selectionArgsList.add("1");
|
||||
}
|
||||
|
||||
String[] selectionArgs = new String[selectionArgsList.size()];
|
||||
selectionArgsList.toArray(selectionArgs);
|
||||
|
||||
try (Cursor evtCursor = mContext.getContentResolver().query(eventsUri, EVENT_INSTANCE_PROJECTION, selection.toString(), selectionArgs, Instances.BEGIN + " ASC")) {
|
||||
if (evtCursor == null || evtCursor.getCount() == 0) {
|
||||
return calendarEventList;
|
||||
}
|
||||
@@ -145,25 +190,39 @@ public class CalendarManager {
|
||||
start,
|
||||
end,
|
||||
evtCursor.getLong(evtCursor.getColumnIndexOrThrow(Instances._ID)),
|
||||
evtCursor.getLong(evtCursor.getColumnIndexOrThrow(Instances.EVENT_ID)),
|
||||
evtCursor.getString(evtCursor.getColumnIndexOrThrow(Instances.TITLE)),
|
||||
evtCursor.getString(evtCursor.getColumnIndexOrThrow(Instances.DESCRIPTION)),
|
||||
evtCursor.getString(evtCursor.getColumnIndexOrThrow(Instances.EVENT_LOCATION)),
|
||||
evtCursor.getString(evtCursor.getColumnIndexOrThrow(Instances.CALENDAR_DISPLAY_NAME)),
|
||||
evtCursor.getString(evtCursor.getColumnIndexOrThrow(CalendarContract.Calendars.ACCOUNT_NAME)),
|
||||
evtCursor.getInt(evtCursor.getColumnIndexOrThrow(Instances.CALENDAR_COLOR)),
|
||||
evtCursor.getInt(evtCursor.getColumnIndexOrThrow(Instances.EVENT_COLOR)),
|
||||
!evtCursor.getString(evtCursor.getColumnIndexOrThrow(Instances.ALL_DAY)).equals("0"),
|
||||
evtCursor.getString(evtCursor.getColumnIndexOrThrow(Instances.ORGANIZER)),
|
||||
evtCursor.getString(evtCursor.getColumnIndexOrThrow(CalendarContract.Calendars.ACCOUNT_TYPE)),
|
||||
evtCursor.getString(evtCursor.getColumnIndexOrThrow(Instances.CALENDAR_ID)),
|
||||
evtCursor.getString(evtCursor.getColumnIndexOrThrow(Instances.RRULE))
|
||||
evtCursor.getString(evtCursor.getColumnIndexOrThrow(Instances.RRULE)),
|
||||
evtCursor.getInt(evtCursor.getColumnIndexOrThrow(Instances.STATUS)),
|
||||
evtCursor.getInt(evtCursor.getColumnIndexOrThrow(Instances.SELF_ATTENDEE_STATUS))
|
||||
);
|
||||
|
||||
|
||||
// Filter now to avoid any reminder looking up the reminders.
|
||||
boolean hasExtendedProperties = evtCursor.getInt(evtCursor.getColumnIndexOrThrow(Instances.HAS_EXTENDED_PROPERTIES)) != 0;
|
||||
if (isCalendarBlacklisted(calEvent.getUniqueCalName()) ||
|
||||
isColorBlacklistedForCalendar(calEvent.getUniqueCalName(), calEvent.getColor()) ||
|
||||
(hasExtendedProperties && isExtendedPropertyBlacklisted(calEvent.getEventId()))) {
|
||||
LOG.debug("event {} - {} skipped because it's blacklisted or filtered", calEvent.getUniqueCalName(), calEvent.getTitle());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Query reminders for this event
|
||||
try (Cursor reminderCursor = mContext.getContentResolver().query(
|
||||
CalendarContract.Reminders.CONTENT_URI,
|
||||
null,
|
||||
CalendarContract.Reminders.EVENT_ID + " = ?",
|
||||
new String[]{String.valueOf(evtCursor.getLong(evtCursor.getColumnIndexOrThrow(Instances.EVENT_ID)))},
|
||||
new String[]{String.valueOf(calEvent.getEventId())},
|
||||
null
|
||||
)) {
|
||||
if (reminderCursor != null && reminderCursor.getCount() > 0) {
|
||||
@@ -185,11 +244,7 @@ public class CalendarManager {
|
||||
LOG.warn("failed to get reminder for event", e);
|
||||
}
|
||||
|
||||
if (!calendarIsBlacklisted(calEvent.getUniqueCalName())) {
|
||||
calendarEventList.add(calEvent);
|
||||
} else {
|
||||
LOG.debug("calendar {} skipped because it's blacklisted", calEvent.getUniqueCalName());
|
||||
}
|
||||
calendarEventList.add(calEvent);
|
||||
}
|
||||
return calendarEventList;
|
||||
} catch (final Exception e) {
|
||||
@@ -234,17 +289,21 @@ public class CalendarManager {
|
||||
startTimestampUtc,
|
||||
startTimestampUtc + 86400000L - 1L,
|
||||
contactId.hashCode(),
|
||||
contactId.hashCode(),
|
||||
mContext.getString(R.string.contact_birthday, displayName),
|
||||
null,
|
||||
null,
|
||||
mContext.getString(R.string.birthdays),
|
||||
mContext.getString(R.string.pref_contacts_title),
|
||||
0,
|
||||
0,
|
||||
true,
|
||||
null,
|
||||
CalendarContract.ACCOUNT_TYPE_LOCAL,
|
||||
null,
|
||||
null
|
||||
null,
|
||||
0,
|
||||
0
|
||||
));
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
@@ -278,28 +337,90 @@ public class CalendarManager {
|
||||
return birthday.plusYears(1);
|
||||
}
|
||||
|
||||
private static HashSet<String> calendars_blacklist = null;
|
||||
public List<CalendarEntry> getCalendars() {
|
||||
final String[] COLOR_PROJECTION = new String[] {
|
||||
CalendarContract.Colors.COLOR, CalendarContract.Colors.ACCOUNT_NAME
|
||||
};
|
||||
|
||||
public boolean calendarIsBlacklisted(String calendarUniqueName) {
|
||||
if (calendars_blacklist == null) {
|
||||
LOG.warn("calendarIsBlacklisted: calendars_blacklist is null!");
|
||||
final String COLOR_SELECTION = CalendarContract.Colors.COLOR_TYPE + " = " + CalendarContract.Colors.TYPE_EVENT;
|
||||
|
||||
Map<String, Set<Integer>> eventColors = new HashMap<>();
|
||||
try (Cursor colorCursor = mContext.getContentResolver().query(CalendarContract.Colors.CONTENT_URI, COLOR_PROJECTION, COLOR_SELECTION, null, CalendarContract.Colors.ACCOUNT_NAME)) {
|
||||
if (colorCursor != null && colorCursor.getCount() > 0) {
|
||||
while (colorCursor.moveToNext()) {
|
||||
final int color = colorCursor.getInt(colorCursor.getColumnIndexOrThrow(CalendarContract.Colors.COLOR));
|
||||
final String account = colorCursor.getString(colorCursor.getColumnIndexOrThrow(CalendarContract.Colors.ACCOUNT_NAME));
|
||||
if (eventColors.containsKey(account)) {
|
||||
eventColors.get(account).add(color);
|
||||
} else {
|
||||
// Some events have no color, aka 0, add that as an option to all lists.
|
||||
eventColors.put(account, new HashSet<>(List.of(0, color)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
LOG.warn("failed to getting colors", e);
|
||||
}
|
||||
return calendars_blacklist != null && calendars_blacklist.contains(calendarUniqueName);
|
||||
|
||||
final String[] CALENDAR_PROJECTION = new String[]{
|
||||
CalendarContract.Calendars.CALENDAR_DISPLAY_NAME,
|
||||
CalendarContract.Calendars.ACCOUNT_NAME,
|
||||
CalendarContract.Calendars.CALENDAR_COLOR
|
||||
};
|
||||
|
||||
ArrayList<CalendarEntry> out = new ArrayList<>();
|
||||
try (Cursor cur = mContext.getContentResolver().query(
|
||||
CalendarContract.Calendars.CONTENT_URI, CALENDAR_PROJECTION, null, null, null)) {
|
||||
while (cur != null && cur.moveToNext()) {
|
||||
out.add(new CalendarEntry(cur.getString(0),
|
||||
cur.getString(1),
|
||||
cur.getInt(2),
|
||||
eventColors.getOrDefault(cur.getString(1),
|
||||
new HashSet<>(List.of()))));
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
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);
|
||||
private boolean isExtendedPropertyBlacklisted(long eventId) {
|
||||
final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(deviceAddress));
|
||||
boolean filterFocusTime = !prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_CALENDAR_SYNC_FOCUS_TIME, true);
|
||||
boolean filterWorkingLocations = !prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_CALENDAR_SYNC_WORKING_LOCATION, true);
|
||||
|
||||
// If both filters are disabled, or the API level is not high enough, no need to even try
|
||||
// querying the properties table.
|
||||
if (!filterFocusTime && !filterWorkingLocations) {
|
||||
return false;
|
||||
}
|
||||
LOG.info("New calendars_blacklist has {} entries", calendars_blacklist.size());
|
||||
saveCalendarsBlackList();
|
||||
|
||||
try (Cursor propCursor = mContext.getContentResolver().query(
|
||||
CalendarContract.ExtendedProperties.CONTENT_URI,
|
||||
new String[] { CalendarContract.ExtendedProperties.VALUE },
|
||||
CalendarContract.Reminders.EVENT_ID + " = ? AND " +
|
||||
CalendarContract.ExtendedProperties.NAME + " = ?",
|
||||
new String[]{ String.valueOf(eventId), "shared:calendarProviderEventType" },
|
||||
null)) {
|
||||
while (propCursor != null && propCursor.moveToNext()) {
|
||||
String propValue = propCursor.getString(propCursor.getColumnIndexOrThrow(CalendarContract.ExtendedProperties.VALUE));
|
||||
if (filterFocusTime && propValue.equals("USER_STATUS_FOCUS_TIME")) {
|
||||
return true;
|
||||
} else if (filterWorkingLocations && propValue.equals("WORKING_LOCATION")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isCalendarBlacklisted(String calendarUniqueName) {
|
||||
if (calendarBlacklist == null) {
|
||||
LOG.warn("isCalendarBlacklisted: calendarBlacklist is null!");
|
||||
}
|
||||
return calendarBlacklist != null && calendarBlacklist.contains(calendarUniqueName);
|
||||
}
|
||||
|
||||
public void addCalendarToBlacklist(String calendarUniqueName) {
|
||||
if (calendars_blacklist.add(calendarUniqueName)) {
|
||||
if (calendarBlacklist.add(calendarUniqueName)) {
|
||||
LOG.info("Blacklisted calendar {}", calendarUniqueName);
|
||||
saveCalendarsBlackList();
|
||||
} else {
|
||||
@@ -308,7 +429,7 @@ public class CalendarManager {
|
||||
}
|
||||
|
||||
public void removeFromCalendarBlacklist(String calendarUniqueName) {
|
||||
calendars_blacklist.remove(calendarUniqueName);
|
||||
calendarBlacklist.remove(calendarUniqueName);
|
||||
LOG.info("Unblacklisted calendar {}", calendarUniqueName);
|
||||
saveCalendarsBlackList();
|
||||
}
|
||||
@@ -316,24 +437,112 @@ public class CalendarManager {
|
||||
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("Loading calendarBlacklist");
|
||||
calendarBlacklist = (HashSet<String>) sharedPrefs.getStringSet(GBPrefs.CALENDAR_BLACKLIST, null);
|
||||
if (calendarBlacklist == null) {
|
||||
calendarBlacklist = new HashSet<>();
|
||||
}
|
||||
LOG.info("Loaded calendars_blacklist has {} entries", calendars_blacklist.size());
|
||||
LOG.info("Loaded calendarBlacklist has {} entries", calendarBlacklist.size());
|
||||
}
|
||||
|
||||
private void saveCalendarsBlackList() {
|
||||
final SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(deviceAddress);
|
||||
|
||||
LOG.info("Saving calendars_blacklist with {} entries", calendars_blacklist.size());
|
||||
LOG.info("Saving calendarBlacklist with {} entries", calendarBlacklist.size());
|
||||
SharedPreferences.Editor editor = sharedPrefs.edit();
|
||||
if (calendars_blacklist.isEmpty()) {
|
||||
if (calendarBlacklist.isEmpty()) {
|
||||
editor.putStringSet(GBPrefs.CALENDAR_BLACKLIST, null);
|
||||
} else {
|
||||
Prefs.putStringSet(editor, GBPrefs.CALENDAR_BLACKLIST, calendars_blacklist);
|
||||
Prefs.putStringSet(editor, GBPrefs.CALENDAR_BLACKLIST, calendarBlacklist);
|
||||
}
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public boolean isColorBlacklistedForCalendar(String calendarUniqueName, int color) {
|
||||
if (colorBlacklist == null) {
|
||||
LOG.warn("isColorBlacklistedForCalendar: colorBlacklist is null!");
|
||||
}
|
||||
return colorBlacklist != null &&
|
||||
colorBlacklist.containsKey(calendarUniqueName) &&
|
||||
colorBlacklist.get(calendarUniqueName).contains(color);
|
||||
}
|
||||
|
||||
public void addColorToBlacklistForCalendar(String calendarUniqueName, int color) {
|
||||
if (colorBlacklist.containsKey(calendarUniqueName)) {
|
||||
if (colorBlacklist.get(calendarUniqueName).add(color)) {
|
||||
LOG.info("Blacklisted color {} {}", calendarUniqueName, color);
|
||||
saveColorBlackList();
|
||||
} else {
|
||||
LOG.warn("Color {} {} already blacklisted!", calendarUniqueName, color);
|
||||
}
|
||||
} else {
|
||||
colorBlacklist.put(calendarUniqueName, new HashSet<>(List.of(color)));
|
||||
LOG.info("Blacklisted color {} {}", calendarUniqueName, color);
|
||||
saveColorBlackList();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeColorFromBlacklistForCalendar(String calendarUniqueName, int color) {
|
||||
if (colorBlacklist.containsKey(calendarUniqueName)) {
|
||||
colorBlacklist.get(calendarUniqueName).remove(color);
|
||||
if (colorBlacklist.get(calendarUniqueName).isEmpty()) {
|
||||
colorBlacklist.remove(calendarUniqueName);
|
||||
}
|
||||
LOG.info("Unblacklisted color {} {}", calendarUniqueName, color);
|
||||
saveColorBlackList();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadColorBlackList() {
|
||||
SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(deviceAddress);
|
||||
colorBlacklist = new HashMap<>();
|
||||
String serializedColorBlackList = sharedPrefs.getString(DeviceSettingsPreferenceConst.PREF_CALENDAR_SYNC_COLOR_BLACKLIST, null);
|
||||
if (serializedColorBlackList != null && !serializedColorBlackList.isEmpty()) {
|
||||
LOG.info("Loading colorBlacklist from json {}", serializedColorBlackList);
|
||||
JSONObject json = null;
|
||||
try {
|
||||
json = new JSONObject(serializedColorBlackList);
|
||||
for (Iterator<String> it = json.keys(); it.hasNext(); ) {
|
||||
String calendarName = it.next();
|
||||
JSONArray colorJson = json.getJSONArray(calendarName);
|
||||
HashSet<Integer> colors = new HashSet<>();
|
||||
for (int i = 0; i < colorJson.length(); i++) {
|
||||
colors.add(colorJson.getInt(i));
|
||||
}
|
||||
colorBlacklist.put(calendarName, colors);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
LOG.warn("Error parsing colors from prefs: {}", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
LOG.info("Loaded colorBlacklist has {} entries", colorBlacklist.size());
|
||||
}
|
||||
|
||||
private void saveColorBlackList() {
|
||||
final SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(deviceAddress);
|
||||
|
||||
LOG.info("Saving colorBlacklist with {} entries", colorBlacklist.size());
|
||||
SharedPreferences.Editor editor = sharedPrefs.edit();
|
||||
if (colorBlacklist.isEmpty()) {
|
||||
editor.putString(DeviceSettingsPreferenceConst.PREF_CALENDAR_SYNC_COLOR_BLACKLIST, null);
|
||||
} else {
|
||||
JSONObject json = new JSONObject();
|
||||
for (Map.Entry<String, HashSet<Integer>> entry : colorBlacklist.entrySet()) {
|
||||
JSONArray colorList = new JSONArray();
|
||||
for (int color : entry.getValue()) {
|
||||
colorList.put(color);
|
||||
}
|
||||
try {
|
||||
json.put(entry.getKey(), colorList);
|
||||
} catch (JSONException e) {
|
||||
LOG.warn("Error serializing colors to prefs: {}", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
editor.putString(DeviceSettingsPreferenceConst.PREF_CALENDAR_SYNC_COLOR_BLACKLIST, json.toString());
|
||||
}
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M20.019 3h-1V1h-2v2h-10V1h-2v2h-1c-1.1 0-2 0.9-2 2v16c0 1.1 0.9 2 2 2h16c1.1 0 2-0.9 2-2V5c0-1.1-0.9-2-2-2zm0 18h-16V10h16zm0-13h-16V5h16z" />
|
||||
|
||||
<path
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeWidth="1.5"
|
||||
android:pathData="M8.5,12l7,7 M15.5,12l-7,7" />
|
||||
</vector>
|
||||
@@ -0,0 +1,16 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_centerHorizontal="true"
|
||||
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.CalendarSelectionActivity">
|
||||
|
||||
<GridView
|
||||
android:id="@+id/calendar_color_selection_list_view"
|
||||
android:numColumns="auto_fit"
|
||||
android:columnWidth="40dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</RelativeLayout>
|
||||
+2
-3
@@ -2,13 +2,12 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.CalBlacklistActivity">
|
||||
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.CalendarSelectionActivity">
|
||||
|
||||
<ListView
|
||||
android:id="@+id/calListView"
|
||||
android:id="@+id/calendar_selection_list_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:divider="@null" />
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -1,60 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/activatedBackgroundIndicator"
|
||||
android:minHeight="60dp">
|
||||
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/item_checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:clickable="false"
|
||||
android:focusable="false" />
|
||||
|
||||
<View
|
||||
android:id="@+id/calendar_color"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_toEndOf="@+id/item_checkbox"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@+id/calendar_color"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/calendar_owner_account"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollHorizontally="false"
|
||||
android:maxLines="1"
|
||||
android:text="TextView"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/calendar_name"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollHorizontally="false"
|
||||
android:maxLines="1"
|
||||
android:text="Item Name" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollHorizontally="false">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/item_event_color"
|
||||
android:padding="8dp"
|
||||
android:layout_marginVertical="1dp"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:focusable="false"
|
||||
android:clickable="false"/>
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:scrollHorizontally="false">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/calendar_entry"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toStartOf="@+id/calendar_color_drop_down"
|
||||
android:layout_alignParentStart="true"
|
||||
android:background="?android:attr/activatedBackgroundIndicator"
|
||||
android:minHeight="56dp">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/item_checkbox"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:clickable="false"
|
||||
android:focusable="false" />
|
||||
|
||||
<View
|
||||
android:id="@+id/calendar_color"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_toEndOf="@+id/item_checkbox"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/calendar_text"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@+id/calendar_color"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/calendar_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:scrollHorizontally="false"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/calendar_owner_account"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:scrollHorizontally="false"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/calendar_color_drop_down"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:focusable="false"
|
||||
android:clickable="false"
|
||||
android:padding="8dp"
|
||||
app:srcCompat="@drawable/ic_more_vert" />
|
||||
</RelativeLayout>
|
||||
@@ -134,8 +134,6 @@
|
||||
<string name="whitelist_all_for_notifications">Whitelist all for notifications</string>
|
||||
<string name="check_all_applications">Check all applications</string>
|
||||
<string name="uncheck_all_applications">Uncheck all applications</string>
|
||||
<!-- Strings related to CalBlacklist -->
|
||||
<string name="title_activity_calblacklist">Blacklisted Calendars</string>
|
||||
<!-- Strings related to FwAppInstaller -->
|
||||
<string name="title_activity_file_installer">File installer</string>
|
||||
<string name="title_activity_fw_app_insaller">FW/App installer</string>
|
||||
@@ -447,8 +445,21 @@
|
||||
<string name="pref_summary_device_intents">Allow Bangle.js watch apps to send Android Intents, and allow other apps on Android (like Tasker) to send data to Bangle.js with the com.banglejs.uart.tx Intent. Needs permission to display over other apps to work in the background.</string>
|
||||
<string name="pref_summary_sync_calendar">Enables calendar alerts, even when disconnected</string>
|
||||
<string name="pref_title_sync_caldendar">Sync calendar events</string>
|
||||
<string name="pref_summary_calendar_sync_choose">Choose which calendars and color labels to sync to the device</string>
|
||||
<string name="pref_title_calendar_sync_choose">Calendars to sync</string>
|
||||
<string name="pref_title_calendar_sync_colors">Event colors to sync</string>
|
||||
<string name="pref_summary_sync_birthdays">Sync contact birthdays alongside calendar events</string>
|
||||
<string name="pref_title_sync_birthdays">Sync birthdays</string>
|
||||
<string name="pref_summary_calendar_sync_canceled">Calendar events that are cancelled will be synced to the device</string>
|
||||
<string name="pref_title_calendar_sync_canceled">Sync canceled events</string>
|
||||
<string name="pref_summary_calendar_sync_declined">Calendar events that you have declined will be synced to the device</string>
|
||||
<string name="pref_title_calendar_sync_declined">Sync declined events</string>
|
||||
<string name="pref_summary_calendar_sync_focus_time">Calendar events that are tagged as \"Focus Time\" will be synced to the device</string>
|
||||
<string name="pref_title_calendar_sync_focus_time">Sync focus time events</string>
|
||||
<string name="pref_summary_calendar_sync_all_day">Calendar events that are marked as \"All Day\" will be synced to the device</string>
|
||||
<string name="pref_title_calendar_sync_all_day">Sync all day events</string>
|
||||
<string name="pref_summary_calendar_sync_working_location">Calendar events that are special \"Working Locations\" will be synced to the device</string>
|
||||
<string name="pref_title_calendar_sync_working_location">Sync working location events</string>
|
||||
<string name="pref_summary_relax_firmware_checks">Relax firmware checks</string>
|
||||
<string name="pref_title_relax_firmware_checks">Enable this if you want to flash a firmware not intended for your device (at your own risk)</string>
|
||||
<string name="pref_title_vibration_strength">Vibration strength</string>
|
||||
@@ -1383,6 +1394,7 @@
|
||||
<string name="delete_device_and_retain_files">Keep Files</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="done">Done</string>
|
||||
<string name="dismiss">Dismiss</string>
|
||||
<string name="notifications_dismiss_all">Dismiss All</string>
|
||||
<string name="start">Start</string>
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_summary_sync_calendar"
|
||||
android:title="@string/pref_title_sync_caldendar" />
|
||||
<Preference
|
||||
android:dependency="sync_calendar"
|
||||
android:icon="@drawable/ic_calendar_month"
|
||||
android:key="calendar_blacklist"
|
||||
android:summary="@string/pref_summary_calendar_sync_choose"
|
||||
android:title="@string/pref_title_calendar_sync_choose" />
|
||||
<EditTextPreference
|
||||
android:defaultValue="7"
|
||||
android:dependency="sync_calendar"
|
||||
@@ -25,10 +31,44 @@
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_summary_sync_birthdays"
|
||||
android:title="@string/pref_title_sync_birthdays" />
|
||||
<Preference
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
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" />
|
||||
android:icon="@drawable/ic_calendar_cancel"
|
||||
android:key="calendar_sync_canceled"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_summary_calendar_sync_canceled"
|
||||
android:title="@string/pref_title_calendar_sync_canceled" />
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:dependency="sync_calendar"
|
||||
android:icon="@drawable/ic_calendar_cancel"
|
||||
android:key="calendar_sync_declined"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_summary_calendar_sync_declined"
|
||||
android:title="@string/pref_title_calendar_sync_declined" />
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:dependency="sync_calendar"
|
||||
android:icon="@drawable/ic_calendar_from"
|
||||
android:key="calendar_sync_all_day"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_summary_calendar_sync_all_day"
|
||||
android:title="@string/pref_title_calendar_sync_all_day" />
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:dependency="sync_calendar"
|
||||
android:icon="@drawable/ic_focus"
|
||||
android:key="calendar_sync_focus_time"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_summary_calendar_sync_focus_time"
|
||||
android:title="@string/pref_title_calendar_sync_focus_time" />
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:dependency="sync_calendar"
|
||||
android:icon="@drawable/ic_gps_location"
|
||||
android:key="calendar_sync_working_location"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_summary_calendar_sync_working_location"
|
||||
android:title="@string/pref_title_calendar_sync_working_location" />
|
||||
</androidx.preference.PreferenceScreen>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.test;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -10,9 +13,6 @@ import nodomain.freeyourgadget.gadgetbridge.externalevents.CalendarReceiver;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarEvent;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
public class CalendarEventTest extends TestBase {
|
||||
private static final long BEGIN = 1;
|
||||
private static final long END = 2;
|
||||
@@ -21,17 +21,18 @@ public class CalendarEventTest extends TestBase {
|
||||
private static final String CALNAME_1 = "cal1";
|
||||
private static final String CALACCOUNTNAME_1 = "account1";
|
||||
private static final int COLOR_1 = 185489;
|
||||
private static final int COLOR_CAL = 0xFF00FF00;
|
||||
|
||||
@Test
|
||||
public void testHashCode() {
|
||||
CalendarEvent c1 =
|
||||
new CalendarEvent(BEGIN, END, ID_1, "something", null, null, CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false, null, null, null, null);
|
||||
new CalendarEvent(BEGIN, END, ID_1, 30,"something", null, null, CALNAME_1, CALACCOUNTNAME_1, COLOR_CAL, COLOR_1, false, null, null, null, null, 0, 1);
|
||||
CalendarEvent c2 =
|
||||
new CalendarEvent(BEGIN, END, ID_1, null, "something", null, CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false, null, null, null, null);
|
||||
new CalendarEvent(BEGIN, END, ID_1, 30,null, "something", null, CALNAME_1, CALACCOUNTNAME_1, COLOR_CAL, COLOR_1, false, null, null, null, null, 3, 0);
|
||||
CalendarEvent c3 =
|
||||
new CalendarEvent(BEGIN, END, ID_1, null, null, "something", CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false, null, null, null, null);
|
||||
new CalendarEvent(BEGIN, END, ID_1, 30, null, null, "something", CALNAME_1, CALACCOUNTNAME_1, COLOR_CAL, COLOR_1, false, null, null, null, null, 2, 2);
|
||||
CalendarEvent c4 =
|
||||
new CalendarEvent(BEGIN, END, ID_1, null, null, "something", CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false, "some", null, null, null);
|
||||
new CalendarEvent(BEGIN, END, ID_1, 30,null, null, "something", CALNAME_1, CALACCOUNTNAME_1, COLOR_CAL, COLOR_1, false, "some", null, null, null, 1, 3);
|
||||
|
||||
assertEquals(c1.hashCode(), c1.hashCode());
|
||||
assertNotEquals(c1.hashCode(), c2.hashCode());
|
||||
@@ -43,7 +44,7 @@ public class CalendarEventTest extends TestBase {
|
||||
@Test
|
||||
public void testSync() {
|
||||
List<CalendarEvent> eventList = new ArrayList<>();
|
||||
eventList.add(new CalendarEvent(BEGIN, END, ID_1, null, "something", null, CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false, null, null, null, null));
|
||||
eventList.add(new CalendarEvent(BEGIN, END, ID_1, 55, null, "something", null, CALNAME_1, CALACCOUNTNAME_1, COLOR_CAL, COLOR_1, false, null, null, null, null, 3, 0));
|
||||
|
||||
GBDevice dummyGBDevice = createDummyGDevice("00:00:01:00:03");
|
||||
dummyGBDevice.setState(GBDevice.State.INITIALIZED);
|
||||
@@ -52,7 +53,7 @@ public class CalendarEventTest extends TestBase {
|
||||
|
||||
testCR.syncCalendar(eventList);
|
||||
|
||||
eventList.add(new CalendarEvent(BEGIN, END, ID_2, null, "something", null, CALNAME_1, CALACCOUNTNAME_1, COLOR_1, false, null, null, null, null));
|
||||
eventList.add(new CalendarEvent(BEGIN, END, ID_2, 63, null, "something", null, CALNAME_1, CALACCOUNTNAME_1, COLOR_CAL, COLOR_1, false, null, null, null, null, 3, 0));
|
||||
testCR.syncCalendar(eventList);
|
||||
|
||||
CalendarSyncStateDao calendarSyncStateDao = daoSession.getCalendarSyncStateDao();
|
||||
|
||||
Reference in New Issue
Block a user