Added option to suppress notifications in a car

This commit is contained in:
M66B 2022-07-06 21:22:02 +02:00
parent e4fe3bcd75
commit 1837cf9dea
5 changed files with 123 additions and 53 deletions

View File

@ -92,6 +92,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
private SwitchCompat swNotifyBackgroundOnly;
private SwitchCompat swNotifyKnownOnly;
private SwitchCompat swNotifySuppressInCall;
private SwitchCompat swNotifySuppressInCar;
private TextView tvNotifyKnownPro;
private SwitchCompat swNotifyRemove;
private SwitchCompat swNotifyClear;
@ -122,7 +123,8 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
"notify_flag", "notify_seen", "notify_hide", "notify_snooze",
"light", "sound", "notify_screen_on",
"badge", "unseen_ignored",
"notify_background_only", "notify_known", "notify_suppress_in_call", "notify_remove", "notify_clear",
"notify_background_only", "notify_known", "notify_suppress_in_call", "notify_suppress_in_car",
"notify_remove", "notify_clear",
"notify_subtext", "notify_preview", "notify_preview_all", "notify_preview_only", "notify_transliterate",
"wearable_preview",
"notify_messaging",
@ -173,6 +175,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
swNotifyBackgroundOnly = view.findViewById(R.id.swNotifyBackgroundOnly);
swNotifyKnownOnly = view.findViewById(R.id.swNotifyKnownOnly);
swNotifySuppressInCall = view.findViewById(R.id.swNotifySuppressInCall);
swNotifySuppressInCar = view.findViewById(R.id.swNotifySuppressInCar);
tvNotifyKnownPro = view.findViewById(R.id.tvNotifyKnownPro);
swNotifyRemove = view.findViewById(R.id.swNotifyRemove);
swNotifyClear = view.findViewById(R.id.swNotifyClear);
@ -478,6 +481,16 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
}
});
swNotifySuppressInCar.setVisibility(
Build.VERSION.SDK_INT < Build.VERSION_CODES.M
? View.GONE : View.VISIBLE);
swNotifySuppressInCar.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("notify_suppress_in_car", checked).apply();
}
});
swNotifyRemove.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
@ -689,6 +702,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
swNotifyBackgroundOnly.setChecked(prefs.getBoolean("notify_background_only", false));
swNotifyKnownOnly.setChecked(prefs.getBoolean("notify_known", false));
swNotifySuppressInCall.setChecked(prefs.getBoolean("notify_suppress_in_call", false));
swNotifySuppressInCar.setChecked(prefs.getBoolean("notify_suppress_in_car", false));
swNotifyRemove.setChecked(prefs.getBoolean("notify_remove", true));
swNotifyClear.setChecked(prefs.getBoolean("notify_clear", false));
swNotifySubtext.setChecked(prefs.getBoolean("notify_subtext", true));

View File

@ -5,6 +5,12 @@ import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.OnLifecycleEvent;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
@ -79,6 +85,51 @@ public class MediaPlayerHelper {
}
}
static void liveInCall(Context context, LifecycleOwner owner, IInCall intf) {
AudioManager am = Helper.getSystemService(context, AudioManager.class);
if (am == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
intf.onChanged(false);
Log.i("Audio mode legacy");
} else {
AudioManager.OnModeChangedListener listener = new AudioManager.OnModeChangedListener() {
@Override
public void onModeChanged(int mode) {
ApplicationEx.getMainHandler().post(new RunnableEx("AudioMode") {
@Override
public void delegate() {
intf.onChanged(isInCall(mode));
}
});
}
};
listener.onModeChanged(am.getMode()); // Init
owner.getLifecycle().addObserver(new LifecycleObserver() {
private boolean registered = false;
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
public void onStateChanged() {
try {
if (owner.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
if (!registered) {
am.addOnModeChangedListener(executor, listener);
registered = true;
}
} else {
if (registered) {
am.removeOnModeChangedListener(listener);
registered = false;
}
}
Log.i("Audio mode registered=" + registered);
} catch (Throwable ex) {
Log.e(ex);
}
}
});
}
}
static boolean isInCall(Context context) {
AudioManager am = Helper.getSystemService(context, AudioManager.class);
if (am == null)
@ -100,4 +151,8 @@ public class MediaPlayerHelper {
mode == AudioManager.MODE_IN_CALL ||
mode == AudioManager.MODE_IN_COMMUNICATION);
}
interface IInCall {
void onChanged(boolean inCall);
}
}

View File

@ -31,7 +31,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
@ -46,6 +45,7 @@ import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.car.app.connection.CarConnection;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.Lifecycle;
@ -116,6 +116,8 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
private int lastAccounts = 0;
private int lastOperations = 0;
private ConnectionHelper.NetworkState lastNetworkState = null;
private boolean isInCall = false;
private boolean isInCar = false;
private boolean foreground = false;
private final Map<Long, Core.State> coreStates = new Hashtable<>();
@ -768,58 +770,45 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
});
final TwoStateOwner mowner = new TwoStateOwner(this, "mutableUnseenNotify");
mowner.getLifecycle().addObserver(new LifecycleObserver() {
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
public void onStateChanged() {
Lifecycle.State state = mowner.getLifecycle().getCurrentState();
EntityLog.log(ServiceSynchronize.this, EntityLog.Type.Debug, "Owner state=" + state);
if (state.equals(Lifecycle.State.DESTROYED))
mowner.getLifecycle().removeObserver(this);
}
});
AudioManager am = Helper.getSystemService(this, AudioManager.class);
if (am == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
mowner.start();
Log.i("Audio mode legacy");
} else {
AudioManager.OnModeChangedListener listener = new AudioManager.OnModeChangedListener() {
@Override
public void onModeChanged(int mode) {
getMainHandler().post(new RunnableEx("AudioMode") {
@Override
public void delegate() {
boolean incall = MediaPlayerHelper.isInCall(mode);
boolean suppress = prefs.getBoolean("notify_suppress_in_call", false);
boolean start = (!suppress || !incall);
Log.i("Audio mode start=" + start +
" incall=" + incall +
" suppress=" + suppress);
if (start)
mowner.start();
else
mowner.stop();
}
});
}
};
listener.onModeChanged(am.getMode()); // Init
MediaPlayerHelper.liveInCall(this, this, new MediaPlayerHelper.IInCall() {
@Override
public void onChanged(boolean inCall) {
boolean suppress = prefs.getBoolean("notify_suppress_in_call", false);
EntityLog.log(ServiceSynchronize.this, EntityLog.Type.Debug,
"In call=" + inCall + " suppress=" + suppress);
isInCall = (inCall && suppress);
if (isInCall || isInCar)
mowner.stop();
else
mowner.start();
}
});
getLifecycle().addObserver(new LifecycleObserver() {
private boolean registered = false;
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
public void onStateChanged() {
try {
if (ServiceSynchronize.this.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
if (!registered) {
am.addOnModeChangedListener(executor, listener);
registered = true;
}
} else {
if (registered) {
am.removeOnModeChangedListener(listener);
registered = false;
}
}
Log.i("Audio mode registered=" + registered);
} catch (Throwable ex) {
Log.e(ex);
}
}
});
}
new CarConnection(this).getType().observe(this, new Observer<Integer>() {
@Override
public void onChanged(Integer connectionState) {
boolean projection = (connectionState != null &&
connectionState == CarConnection.CONNECTION_TYPE_PROJECTION);
boolean suppress = prefs.getBoolean("notify_suppress_in_car", false);
EntityLog.log(ServiceSynchronize.this, EntityLog.Type.Debug,
"Projection=" + projection + " state=" + connectionState + " suppress=" + suppress);
isInCar = (projection && suppress);
if (isInCall || isInCar)
mowner.stop();
else
mowner.start();
}
});
mutableUnseenNotify.observe(mowner, new Observer<List<TupleMessageEx>>() {
private final ExecutorService executor =

View File

@ -560,6 +560,17 @@
app:layout_constraintTop_toBottomOf="@id/tvNotifyKnownPro"
app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swNotifySuppressInCar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_advanced_notify_suppress_in_car"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swNotifySuppressInCall"
app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swNotifyRemove"
android:layout_width="0dp"
@ -569,7 +580,7 @@
android:text="@string/title_advanced_notify_remove"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swNotifySuppressInCall"
app:layout_constraintTop_toBottomOf="@id/swNotifySuppressInCar"
app:switchPadding="12dp" />
<TextView

View File

@ -622,6 +622,7 @@
<string name="title_advanced_notify_background">Show notifications when in the background only</string>
<string name="title_advanced_notify_known">Show notifications for contacts only</string>
<string name="title_advanced_notify_suppress_in_call">Delay notifications while on a call</string>
<string name="title_advanced_notify_suppress_in_car">Delay notifications while Android Auto is connected</string>
<string name="title_advanced_notify_summary">Show summary notification only</string>
<string name="title_advanced_notify_preview">Show message preview in notifications</string>
<string name="title_advanced_notify_preview_all">Preview all text</string>