Pebble: allow to blacklist certain calendars

As requested in #736, this adds an entry in the settings menu that allows to blacklist certain calendars.
To avoid confusion, all the former blacklist methods and fields have been renamed to apps_blacklist. The new entries are called calendars_blacklist.
Importing the settings has not been tested with the current changes.
Closes #736

Future improvements TODO: The new setting lives in the Pebble section, i believe in the future the blackslist functionality should be centralized and put in the sidebar.
master
Daniele Gobbetti 2017-08-18 10:30:19 +02:00
parent 6c38c6bb79
commit 8cce2d1362
16 changed files with 350 additions and 49 deletions

View File

@ -7,6 +7,7 @@
* Handle resetting language to default properly
* Pebble: Pass booleans from Javascript Appmessage correctly
* Pebble: Make local configuration pages work on most recent webview implementation
* Pebble: Allow to blacklist calendars
* Add greek transliteration support
* Various visual improvements to charts

View File

@ -63,6 +63,10 @@
android:name=".activities.AppBlacklistActivity"
android:label="@string/title_activity_appblacklist"
android:parentActivityName=".activities.SettingsActivity" />
<activity
android:name=".activities.CalBlacklistActivity"
android:label="@string/title_activity_calblacklist"
android:parentActivityName=".activities.SettingsActivity" />
<activity
android:name=".activities.FwAppInstallerActivity"
android:label="@string/title_activity_fw_app_insaller"

View File

@ -165,7 +165,8 @@ public class GBApplication extends Application {
setLanguage(language);
deviceService = createDeviceService();
loadBlackList();
loadAppsBlackList();
loadCalendarsBlackList();
if (isRunningMarshmallowOrLater()) {
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
@ -341,56 +342,107 @@ public class GBApplication extends Application {
return NotificationManager.INTERRUPTION_FILTER_ALL;
}
private static HashSet<String> blacklist = null;
private static HashSet<String> apps_blacklist = null;
public static boolean isBlacklisted(String packageName) {
if (blacklist == null) {
GB.log("isBlacklisted: blacklisti is null!", GB.INFO, null);
public static boolean appIsBlacklisted(String packageName) {
if (apps_blacklist == null) {
GB.log("appIsBlacklisted: apps_blacklist is null!", GB.INFO, null);
}
return blacklist != null && blacklist.contains(packageName);
return apps_blacklist != null && apps_blacklist.contains(packageName);
}
public static void setBlackList(Set<String> packageNames) {
public static void setAppsBlackList(Set<String> packageNames) {
if (packageNames == null) {
GB.log("Set null blacklist", GB.INFO, null);
blacklist = new HashSet<>();
GB.log("Set null apps_blacklist", GB.INFO, null);
apps_blacklist = new HashSet<>();
} else {
blacklist = new HashSet<>(packageNames);
apps_blacklist = new HashSet<>(packageNames);
}
GB.log("New blacklist has " + blacklist.size() + " entries", GB.INFO, null);
saveBlackList();
GB.log("New apps_blacklist has " + apps_blacklist.size() + " entries", GB.INFO, null);
saveAppsBlackList();
}
private static void loadBlackList() {
GB.log("Loading blacklist", GB.INFO, null);
blacklist = (HashSet<String>) sharedPrefs.getStringSet(GBPrefs.PACKAGE_BLACKLIST, null);
if (blacklist == null) {
blacklist = new HashSet<>();
private static void loadAppsBlackList() {
GB.log("Loading apps_blacklist", GB.INFO, null);
apps_blacklist = (HashSet<String>) sharedPrefs.getStringSet(GBPrefs.PACKAGE_BLACKLIST, null);
if (apps_blacklist == null) {
apps_blacklist = new HashSet<>();
}
GB.log("Loaded blacklist has " + blacklist.size() + " entries", GB.INFO, null);
GB.log("Loaded apps_blacklist has " + apps_blacklist.size() + " entries", GB.INFO, null);
}
private static void saveBlackList() {
GB.log("Saving blacklist with " + blacklist.size() + " entries", GB.INFO, null);
private static void saveAppsBlackList() {
GB.log("Saving apps_blacklist with " + apps_blacklist.size() + " entries", GB.INFO, null);
SharedPreferences.Editor editor = sharedPrefs.edit();
if (blacklist.isEmpty()) {
if (apps_blacklist.isEmpty()) {
editor.putStringSet(GBPrefs.PACKAGE_BLACKLIST, null);
} else {
Prefs.putStringSet(editor, GBPrefs.PACKAGE_BLACKLIST, blacklist);
Prefs.putStringSet(editor, GBPrefs.PACKAGE_BLACKLIST, apps_blacklist);
}
editor.apply();
}
public static void addToBlacklist(String packageName) {
if (blacklist.add(packageName)) {
saveBlackList();
public static void addAppToBlacklist(String packageName) {
if (apps_blacklist.add(packageName)) {
saveAppsBlackList();
}
}
public static synchronized void removeFromBlacklist(String packageName) {
GB.log("Removing from blacklist: " + packageName, GB.INFO, null);
blacklist.remove(packageName);
saveBlackList();
public static synchronized void removeFromAppsBlacklist(String packageName) {
GB.log("Removing from apps_blacklist: " + packageName, GB.INFO, null);
apps_blacklist.remove(packageName);
saveAppsBlackList();
}
private static HashSet<String> calendars_blacklist = null;
public static boolean calendarIsBlacklisted(String calendarDisplayName) {
if (calendars_blacklist == null) {
GB.log("calendarIsBlacklisted: calendars_blacklist is null!", GB.INFO, null);
}
return calendars_blacklist != null && calendars_blacklist.contains(calendarDisplayName);
}
public static void setCalendarsBlackList(Set<String> calendarNames) {
if (calendarNames == null) {
GB.log("Set null apps_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 calendarDisplayName) {
if (calendars_blacklist.add(calendarDisplayName)) {
saveCalendarsBlackList();
}
}
public static void removeFromCalendarBlacklist(String calendarDisplayName) {
calendars_blacklist.remove(calendarDisplayName);
saveCalendarsBlackList();
}
private static void loadCalendarsBlackList() {
GB.log("Loading calendars_blacklist", GB.INFO, null);
calendars_blacklist = (HashSet<String>) sharedPrefs.getStringSet(GBPrefs.CALENDAR_BLACKLIST, null);
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();
}
/**

View File

@ -0,0 +1,152 @@
/* Copyright (C) 2017 Daniele Gobbetti
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.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.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.NavUtils;
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 nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
public class CalBlacklistActivity extends GBActivity {
private final String[] EVENT_PROJECTION = new String[]{
CalendarContract.Calendars.CALENDAR_DISPLAY_NAME,
CalendarContract.Calendars.CALENDAR_COLOR
};
private ArrayList<Calendar> calendarsArrayList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_calblacklist);
ListView calListView = (ListView) findViewById(R.id.calListView);
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.getInt(1)));
}
}
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()) {
GBApplication.addCalendarToBlacklist(item.displayName);
} else {
GBApplication.removeFromCalendarBlacklist(item.displayName);
}
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case 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 int color;
public Calendar(String displayName, int color) {
this.displayName = displayName;
this.color = color;
}
}
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);
CheckBox checked = (CheckBox) view.findViewById(R.id.item_checkbox);
if (GBApplication.calendarIsBlacklisted(item.displayName) && !checked.isChecked()) {
toggleEntry(view);
}
color.setBackgroundColor(item.color);
name.setText(item.displayName);
return view;
}
}
}

View File

@ -97,6 +97,15 @@ 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.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override

View File

@ -62,7 +62,7 @@ public class AppBlacklistAdapter extends RecyclerView.Adapter<AppBlacklistAdapte
if (name == null) {
name = ai.packageName;
}
if (GBApplication.isBlacklisted(ai.packageName)) {
if (GBApplication.appIsBlacklisted(ai.packageName)) {
// sort blacklisted first by prefixing with a '!'
name = "!" + name;
}
@ -94,7 +94,7 @@ public class AppBlacklistAdapter extends RecyclerView.Adapter<AppBlacklistAdapte
holder.deviceAppNameLabel.setText(mNameMap.get(appInfo));
holder.deviceImageView.setImageDrawable(appInfo.loadIcon(mPm));
holder.checkbox.setChecked(GBApplication.isBlacklisted(appInfo.packageName));
holder.checkbox.setChecked(GBApplication.appIsBlacklisted(appInfo.packageName));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
@ -102,9 +102,9 @@ public class AppBlacklistAdapter extends RecyclerView.Adapter<AppBlacklistAdapte
CheckBox checkBox = ((CheckBox) v.findViewById(R.id.item_checkbox));
checkBox.toggle();
if (checkBox.isChecked()) {
GBApplication.addToBlacklist(appInfo.packageName);
GBApplication.addAppToBlacklist(appInfo.packageName);
} else {
GBApplication.removeFromBlacklist(appInfo.packageName);
GBApplication.removeFromAppsBlacklist(appInfo.packageName);
}
}
});

View File

@ -34,7 +34,6 @@ import java.util.List;
import de.greenrobot.dao.query.QueryBuilder;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.GBException;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.entities.CalendarSyncState;

View File

@ -103,7 +103,7 @@ public class NotificationListener extends NotificationListenerService {
} else {
// ACTION_MUTE
LOG.info("going to mute " + sbn.getPackageName());
GBApplication.addToBlacklist(sbn.getPackageName());
GBApplication.addAppToBlacklist(sbn.getPackageName());
}
}
}
@ -414,7 +414,7 @@ public class NotificationListener extends NotificationListenerService {
}
}
if (GBApplication.isBlacklisted(source)) {
if (GBApplication.appIsBlacklisted(source)) {
LOG.info("Ignoring notification, application is blacklisted");
return true;
}

View File

@ -23,7 +23,6 @@ import android.database.Cursor;
import android.net.Uri;
import android.provider.CalendarContract.Instances;
import android.text.format.Time;
import android.util.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -34,6 +33,8 @@ 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);
@ -102,7 +103,11 @@ public class CalendarEvents {
evtCursor.getString(7),
!evtCursor.getString(8).equals("0")
);
calendarEventList.add(calEvent);
if (!GBApplication.calendarIsBlacklisted(calEvent.getCalName())) {
calendarEventList.add(calEvent);
} else {
LOG.debug("calendar " + calEvent.getCalName() + " skipped because it's blacklisted");
}
}
return true;
}

View File

@ -21,6 +21,7 @@ import java.util.Date;
public class GBPrefs {
public static final String PACKAGE_BLACKLIST = "package_blacklist";
public static final String CALENDAR_BLACKLIST = "calendar_blacklist";
public static final String AUTO_RECONNECT = "general_autocreconnect";
private static final String AUTO_START = "general_autostartonboot";
private static final boolean AUTO_START_DEFAULT = true;

View File

@ -17,6 +17,12 @@
package nodomain.freeyourgadget.gadgetbridge.util;
import android.content.SharedPreferences;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
@ -27,12 +33,6 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import android.content.SharedPreferences;
import android.util.Xml;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
public class ImportExportSharedPreferences {
@ -125,12 +125,19 @@ public class ImportExportSharedPreferences {
editor.putString(key, text);
} else if (HASHSET.equals(name)) {
if (key.equals(GBPrefs.PACKAGE_BLACKLIST)) {
Set<String> blacklist = new HashSet<>();
Set<String> apps_blacklist = new HashSet<>();
text=text.replace("[","").replace("]","");
for (int z=0;z<text.split(",").length;z++){
blacklist.add(text.split(",")[z].trim());
apps_blacklist.add(text.split(",")[z].trim());
}
GBApplication.setBlackList(blacklist);
GBApplication.setAppsBlackList(apps_blacklist);
} else if (key.equals(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);
}
} else if (!PREFERENCES.equals(name)) {
throw new Exception("Unkown type " + name);

View File

@ -0,0 +1,14 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.CalBlacklistActivity">
<ListView
android:id="@+id/calListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:divider="@null" />
</RelativeLayout>

View File

@ -0,0 +1,50 @@
<?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:paddingBottom="8dp"
android:paddingTop="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_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>

View File

@ -46,6 +46,9 @@
<!-- Strings related to AppBlacklist -->
<string name="title_activity_appblacklist">Notification Blacklist</string>
<!-- Strings related to CalBlacklist -->
<string name="title_activity_calblacklist">Blacklisted Calendars</string>
<!-- Strings related to FwAppInstaller -->
<string name="title_activity_fw_app_insaller">FW/App installer</string>
<string name="fw_upgrade_notice">You are about to install firmware %s instead of the one currently on your Mi Band.</string>
@ -104,6 +107,7 @@
<string name="pref_blacklist">Blacklist Apps</string>
<string name="pref_blacklist_calendars">Blacklist Calendars</string>
<string name="pref_header_cannned_messages">Canned Messages</string>
<string name="pref_title_canned_replies">Replies</string>

View File

@ -8,8 +8,8 @@
<change>Add workaround for blacklist not properly persisting</change>
<change>Handle resetting language to default properly</change>
<change>Pebble: Pass booleans from Javascript Appmessage correctly</change>
<change>Pebble: Make local configuration pages work on most recent webview implementation
</change>
<change>Pebble: Make local configuration pages work on most recent webview implementation</change>
<change>Pebble: Allow to blacklist calendars</change>
<change>Add greek transliteration support</change>
<change>Various visual improvements to charts</change>
</release>

View File

@ -208,6 +208,9 @@
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:key="send_sunrise_sunset"
android:summary="@string/pref_summary_sunrise_sunset"