diff --git a/app/src/main/java/eu/faircode/email/ActivitySetup.java b/app/src/main/java/eu/faircode/email/ActivitySetup.java index 99b3160a69..092a8ab1ce 100644 --- a/app/src/main/java/eu/faircode/email/ActivitySetup.java +++ b/app/src/main/java/eu/faircode/email/ActivitySetup.java @@ -30,6 +30,7 @@ import android.content.pm.PackageManager; import android.content.res.AssetFileDescriptor; import android.content.res.Configuration; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.text.TextUtils; @@ -538,6 +539,8 @@ public class ActivitySetup extends ActivityBilling implements FragmentManager.On jexport.put("accounts", jaccounts); jexport.put("answers", janswers); jexport.put("settings", jsettings); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + jexport.put("channels", ((ApplicationEx) getApplication()).channelsToJSON()); ContentResolver resolver = context.getContentResolver(); DocumentFile file = DocumentFile.fromSingleUri(context, uri); @@ -749,6 +752,12 @@ public class ActivitySetup extends ActivityBilling implements FragmentManager.On } editor.apply(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + if (jimport.has("channels")) { + JSONArray jchannels = jimport.getJSONArray("channels"); + ((ApplicationEx) getApplication()).channelsFromJSON(jchannels); + } + db.setTransactionSuccessful(); } finally { db.endTransaction(); diff --git a/app/src/main/java/eu/faircode/email/ApplicationEx.java b/app/src/main/java/eu/faircode/email/ApplicationEx.java index 5ddc85ff29..a86e5173b7 100644 --- a/app/src/main/java/eu/faircode/email/ApplicationEx.java +++ b/app/src/main/java/eu/faircode/email/ApplicationEx.java @@ -24,19 +24,35 @@ import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Context; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; import android.os.Build; import android.os.DeadSystemException; import android.os.RemoteException; import android.webkit.CookieManager; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; import java.util.Date; +import java.util.List; + +import androidx.annotation.RequiresApi; public class ApplicationEx extends Application { private Thread.UncaughtExceptionHandler prev = null; + private static final List DEFAULT_CHANNEL_NAMES = Collections.unmodifiableList(Arrays.asList( + "service", "notification", "warning", "error" + )); + @Override public void onCreate() { super.onCreate(); @@ -104,6 +120,81 @@ public class ApplicationEx extends Application { } } + @RequiresApi(api = Build.VERSION_CODES.O) + public JSONArray channelsToJSON() throws JSONException { + JSONArray jchannels = new JSONArray(); + + NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + for (NotificationChannel channel : nm.getNotificationChannels()) + if (!DEFAULT_CHANNEL_NAMES.contains(channel.getId())) { + JSONObject jchannel = new JSONObject(); + + jchannel.put("id", channel.getId()); + jchannel.put("group", channel.getGroup()); + jchannel.put("name", channel.getName()); + jchannel.put("description", channel.getDescription()); + + jchannel.put("importance", channel.getImportance()); + jchannel.put("dnd", channel.canBypassDnd()); + jchannel.put("visibility", channel.getLockscreenVisibility()); + jchannel.put("badge", channel.canShowBadge()); + + Uri sound = channel.getSound(); + if (sound != null) + jchannel.put("sound", sound.toString()); + // audio attributes + + jchannel.put("light", channel.shouldShowLights()); + // color + + jchannel.put("vibrate", channel.shouldVibrate()); + // pattern + + jchannels.put(jchannel); + } + + return jchannels; + } + + @RequiresApi(api = Build.VERSION_CODES.O) + public void channelsFromJSON(JSONArray jchannels) throws JSONException { + NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + for (int c = 0; c < jchannels.length(); c++) { + JSONObject jchannel = (JSONObject) jchannels.get(c); + + String id = jchannel.getString("id"); + if (nm.getNotificationChannel(id) == null) { + NotificationChannel channel = new NotificationChannel( + id, + jchannel.getString("name"), + jchannel.getInt("importance")); + + if (jchannel.has("group") && !jchannel.isNull("group")) + channel.setGroup(jchannel.getString("group")); + + if (jchannel.has("description") && !jchannel.isNull("description")) + channel.setDescription(jchannel.getString("description")); + + channel.setBypassDnd(jchannel.getBoolean("dnd")); + channel.setLockscreenVisibility(jchannel.getInt("visibility")); + channel.setShowBadge(jchannel.getBoolean("badge")); + + if (jchannel.has("sound") && !jchannel.isNull("sound")) { + Uri uri = Uri.parse(jchannel.getString("sound")); + Ringtone ringtone = RingtoneManager.getRingtone(this, uri); + if (ringtone != null) + channel.setSound(uri, Notification.AUDIO_ATTRIBUTES_DEFAULT); + } + + channel.enableLights(jchannel.getBoolean("light")); + channel.enableVibration(jchannel.getBoolean("vibrate")); + + Log.i("Creating channel=" + channel); + nm.createNotificationChannel(channel); + } + } + } + public boolean ownFault(Throwable ex) { if (ex instanceof OutOfMemoryError) return false;