Skip to content

Commit 0e39975

Browse files
authored
Version 1.1.0 (#3)
* Add modes: filter by notification author count * Add Signal as a known messaging app * Prevent battery optimization dialog from appearing twice
1 parent 12e3343 commit 0e39975

File tree

8 files changed

+155
-4
lines changed

8 files changed

+155
-4
lines changed

app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ android {
99
minSdkVersion 26
1010
targetSdkVersion 30
1111
versionCode 1
12-
versionName "1.0.1"
12+
versionName "1.1.0"
1313

1414
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1515
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.talmar.conveyor;
2+
3+
public enum EchoingMode {
4+
ALL, // All notifications are echoed
5+
GROUPS_ONLY, // Only notifications with 2 or more authors are echoed
6+
DIRECT_MESSAGES_ONLY // Only notifications with 1 or less authors are echoed
7+
}

app/src/main/java/com/talmar/conveyor/SettingsFragment.java

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
import android.provider.Settings;
99
import android.util.Pair;
1010

11+
import androidx.annotation.Nullable;
1112
import androidx.preference.CheckBoxPreference;
13+
import androidx.preference.DropDownPreference;
1214
import androidx.preference.MultiSelectListPreference;
1315
import androidx.preference.Preference;
1416
import androidx.preference.PreferenceFragmentCompat;
@@ -22,6 +24,7 @@
2224
import java.util.HashSet;
2325
import java.util.Set;
2426
import java.util.stream.Collectors;
27+
import java.util.stream.Stream;
2528

2629
public class SettingsFragment extends PreferenceFragmentCompat {
2730
private static final String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
@@ -37,12 +40,22 @@ public class SettingsFragment extends PreferenceFragmentCompat {
3740
"com.facebook.orca", // Facebook Messenger
3841
"com.instagram.android", // Instagram
3942
"com.google.android.apps.messaging", // Messages (by Google)
40-
"com.discord")); // Discord
43+
"com.discord", // Discord
44+
"org.thoughtcrime.securesms")); // Signal
4145

4246
private SwitchPreferenceCompat m_hasNotificationAccessSwitch;
4347
private MultiSelectListPreference m_selectedAppsPreference;
4448
private CheckBoxPreference m_clearNotificationsOnUnlockCheckBox;
4549
private Preference m_openGarminConnectPreference;
50+
private DropDownPreference m_modePreference;
51+
52+
private AlertDialog m_batteryOptimizationDialog;
53+
54+
@Override
55+
public void onCreate(@Nullable Bundle savedInstanceState) {
56+
m_batteryOptimizationDialog = buildBatteryOptimizationAlertDialog();
57+
super.onCreate(savedInstanceState);
58+
}
4659

4760
@Override
4861
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
@@ -52,11 +65,13 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
5265
m_selectedAppsPreference = findPreference("selected_apps");
5366
m_clearNotificationsOnUnlockCheckBox = findPreference("clear_notifications_on_unlock");
5467
m_openGarminConnectPreference = findPreference("open_garmin_connect");
68+
m_modePreference = findPreference("mode");
5569

5670
assert null != m_hasNotificationAccessSwitch;
5771
assert null != m_selectedAppsPreference;
5872
assert null != m_clearNotificationsOnUnlockCheckBox;
5973
assert null != m_openGarminConnectPreference;
74+
assert null != m_modePreference;
6075

6176
populateAppListPreference(m_selectedAppsPreference);
6277
pruneUninstalledAppsFromPreference(m_selectedAppsPreference);
@@ -88,6 +103,29 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
88103
m_openGarminConnectPreference.setSummary(R.string.garmin_connect_tutorial);
89104
}
90105

106+
populateModePreference(m_modePreference);
107+
m_modePreference.setSummaryProvider(
108+
(Preference.SummaryProvider<DropDownPreference>) preference -> {
109+
EchoingMode mode;
110+
try {
111+
mode = EchoingMode.valueOf(preference.getValue());
112+
} catch (IllegalArgumentException e) {
113+
mode = EchoingMode.ALL;
114+
}
115+
116+
int resource = R.string.mode_all_notifications_description;
117+
switch (mode) {
118+
case GROUPS_ONLY:
119+
resource = R.string.mode_groups_only_description;
120+
break;
121+
case DIRECT_MESSAGES_ONLY:
122+
resource = R.string.mode_direct_only_description;
123+
break;
124+
}
125+
126+
return getString(resource);
127+
});
128+
91129
syncPreferencesToSystemState();
92130
}
93131

@@ -104,7 +142,7 @@ private void syncPreferencesToSystemState() {
104142
String packageName = requireContext().getPackageName();
105143
PowerManager powerManager = (PowerManager) requireContext().getSystemService(Context.POWER_SERVICE);
106144
if (!powerManager.isIgnoringBatteryOptimizations(packageName)) {
107-
buildBatteryOptimizationAlertDialog().show();
145+
m_batteryOptimizationDialog.show();
108146
}
109147
}
110148

@@ -189,4 +227,17 @@ private void pruneUninstalledAppsFromPreference(MultiSelectListPreference prefer
189227
Set<String> filteredValues = preference.getValues().stream().filter(installedApps::contains).collect(Collectors.toSet());
190228
preference.setValues(filteredValues);
191229
}
230+
231+
private void populateModePreference(DropDownPreference preference) {
232+
CharSequence[] entries = new CharSequence[3];
233+
entries[0] = getString(R.string.mode_all_notifications);
234+
entries[1] = getString(R.string.mode_groups_only);
235+
entries[2] = getString(R.string.mode_direct_only);
236+
preference.setEntryValues(Stream.of(EchoingMode.values()).map(EchoingMode::name).toArray(CharSequence[]::new));
237+
preference.setEntries(entries);
238+
239+
if (preference.getValue() == null) {
240+
preference.setValue(EchoingMode.ALL.name());
241+
}
242+
}
192243
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.talmar.conveyor.notificationFilters;
2+
3+
import android.app.Notification;
4+
import android.content.SharedPreferences;
5+
import android.service.notification.StatusBarNotification;
6+
7+
import androidx.annotation.NonNull;
8+
9+
import com.talmar.conveyor.EchoingMode;
10+
import com.talmar.conveyor.components.Conversation;
11+
12+
13+
/**
14+
* Filters notifications according to the current echoing mode.
15+
*/
16+
public class ModeFilter implements INotificationFilter, SharedPreferences.OnSharedPreferenceChangeListener {
17+
private static final String MODE_KEY_NAME = "mode";
18+
19+
private EchoingMode m_echoingMode;
20+
21+
public ModeFilter(SharedPreferences sharedPreferences) {
22+
m_echoingMode = getModeFromPreferences(sharedPreferences);
23+
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
24+
}
25+
26+
@Override
27+
public boolean shouldIgnoreNotification(@NonNull StatusBarNotification sbn) {
28+
if (EchoingMode.ALL == m_echoingMode) {
29+
return false;
30+
}
31+
32+
Notification notification = sbn.getNotification();
33+
String notificationTemplate = notification.extras.getString(Notification.EXTRA_TEMPLATE);
34+
boolean isMessagingStyle = Notification.MessagingStyle.class.getName().equals(notificationTemplate);
35+
36+
if (!isMessagingStyle) {
37+
// This is not a messaging-style notification, meaning that we can't determine if it's
38+
// a group or a DM. Ignore it.
39+
return true;
40+
}
41+
42+
Conversation conversation = new Conversation(sbn.getNotification());
43+
boolean hasMultipleAuthors = conversation.getAuthors().size() > 1;
44+
45+
boolean isAllowed = (
46+
hasMultipleAuthors && m_echoingMode == EchoingMode.GROUPS_ONLY
47+
|| !hasMultipleAuthors && m_echoingMode == EchoingMode.DIRECT_MESSAGES_ONLY);
48+
49+
return !isAllowed;
50+
}
51+
52+
@Override
53+
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
54+
if (!key.equals(MODE_KEY_NAME)) {
55+
return;
56+
}
57+
58+
m_echoingMode = getModeFromPreferences(sharedPreferences);
59+
}
60+
61+
private static EchoingMode getModeFromPreferences(SharedPreferences preferences) {
62+
try {
63+
return EchoingMode.valueOf(preferences.getString(MODE_KEY_NAME, EchoingMode.ALL.name()));
64+
} catch (IllegalArgumentException e) {
65+
return EchoingMode.ALL;
66+
}
67+
}
68+
}

app/src/main/java/com/talmar/conveyor/services/NotificationService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.talmar.conveyor.NotificationEchoing;
1717
import com.talmar.conveyor.notificationFilters.CategoryFilter;
1818
import com.talmar.conveyor.notificationFilters.INotificationFilter;
19+
import com.talmar.conveyor.notificationFilters.ModeFilter;
1920
import com.talmar.conveyor.notificationFilters.NullContentFilter;
2021
import com.talmar.conveyor.notificationFilters.OwnNotificationFilter;
2122
import com.talmar.conveyor.notificationFilters.SelectedAppsFilter;
@@ -50,7 +51,8 @@ public void onCreate() {
5051
new CategoryFilter(),
5152
new NullContentFilter(),
5253
new SelectedAppsFilter(sharedPreferences),
53-
new UserPresenceFilter(this, sharedPreferences)
54+
new UserPresenceFilter(this, sharedPreferences),
55+
new ModeFilter(sharedPreferences)
5456
};
5557
}
5658

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24"
6+
android:tint="?attr/colorControlNormal">
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M22.7,19l-9.1,-9.1c0.9,-2.3 0.4,-5 -1.5,-6.9 -2,-2 -5,-2.4 -7.4,-1.3L9,6 6,9 1.6,4.7C0.4,7.1 0.9,10.1 2.9,12.1c1.9,1.9 4.6,2.4 6.9,1.5l9.1,9.1c0.4,0.4 1,0.4 1.4,0l2.3,-2.3c0.5,-0.4 0.5,-1.1 0.1,-1.4z"/>
10+
</vector>

app/src/main/res/values/strings.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,11 @@
2525
<string name="disable_optimization_dialog_message">For this app to work consistently in the background, you must disable battery optimization for it. Please locate this app in the settings and select \"Don\'t optimize\". If your device allows control over app autostart, please enable that as well.</string>
2626
<string name="disable_optimization_dialog_positive">Open Settings</string>
2727
<string name="battery_optimization_active_warning">Battery optimization will make this app unreliable.</string>
28+
<string name="select_mode_title">Select mode</string>
29+
<string name="mode_all_notifications">All notifications</string>
30+
<string name="mode_groups_only">Only group messages</string>
31+
<string name="mode_direct_only">Only direct messages</string>
32+
<string name="mode_all_notifications_description">Echoing all notifications</string>
33+
<string name="mode_groups_only_description">Echoing group messages only</string>
34+
<string name="mode_direct_only_description">Echoing direct messages only</string>
2835
</resources>

app/src/main/res/xml/preferences.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616
android:icon="@drawable/ic_baseline_apps_24"
1717
app:title="@string/select_apps_title" />
1818

19+
<DropDownPreference
20+
app:key="mode"
21+
android:icon="@drawable/ic_baseline_build_24"
22+
app:title="@string/select_mode_title"
23+
app:summary="@string/mode_all_notifications_description" />
24+
1925
<CheckBoxPreference
2026
app:key="clear_notifications_on_unlock"
2127
android:icon="@drawable/ic_baseline_clear_all_24"

0 commit comments

Comments
 (0)