diff --git a/app/src/main/java/eu/faircode/email/ActivitySetup.java b/app/src/main/java/eu/faircode/email/ActivitySetup.java index 4a824a4674..1dacc00eb2 100644 --- a/app/src/main/java/eu/faircode/email/ActivitySetup.java +++ b/app/src/main/java/eu/faircode/email/ActivitySetup.java @@ -22,7 +22,6 @@ package eu.faircode.email; import android.accounts.Account; import android.accounts.AccountManager; import android.app.Dialog; -import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.NotificationManager; @@ -37,8 +36,6 @@ import android.content.res.AssetFileDescriptor; import android.content.res.Configuration; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.media.Ringtone; -import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -51,7 +48,6 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.AlertDialog; import androidx.constraintlayout.widget.ConstraintLayout; @@ -534,7 +530,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac NotificationChannel channel = nm.getNotificationChannel( EntityAccount.getNotificationChannelId(account.id)); if (channel != null && channel.getImportance() != NotificationManager.IMPORTANCE_NONE) { - JSONObject jchannel = channelToJSON(channel); + JSONObject jchannel = NotificationHelper.channelToJSON(channel); jaccount.put("channel", jchannel); Log.i("Exported account channel=" + jchannel); } @@ -556,7 +552,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac NotificationChannel channel = nm.getNotificationChannel( EntityFolder.getNotificationChannelId(folder.id)); if (channel != null && channel.getImportance() != NotificationManager.IMPORTANCE_NONE) { - JSONObject jchannel = channelToJSON(channel); + JSONObject jchannel = NotificationHelper.channelToJSON(channel); jfolder.put("channel", jchannel); Log.i("Exported folder channel=" + jchannel); } @@ -626,7 +622,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac String id = channel.getId(); if (id.startsWith("notification.") && id.contains("@") && channel.getImportance() != NotificationManager.IMPORTANCE_NONE) { - JSONObject jchannel = channelToJSON(channel); + JSONObject jchannel = NotificationHelper.channelToJSON(channel); jchannels.put(jchannel); Log.i("Exported contact channel=" + jchannel); } @@ -817,7 +813,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac JSONObject jchannel = (JSONObject) jaccount.get("channel"); jchannel.put("id", EntityAccount.getNotificationChannelId(account.id)); jchannel.put("group", group.getId()); - nm.createNotificationChannel(channelFromJSON(context, jchannel)); + nm.createNotificationChannel(NotificationHelper.channelFromJSON(context, jchannel)); Log.i("Imported account channel=" + jchannel); } else @@ -867,7 +863,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac JSONObject jchannel = (JSONObject) jfolder.get("channel"); jchannel.put("id", channelId); jchannel.put("group", group.getId()); - nm.createNotificationChannel(channelFromJSON(context, jchannel)); + nm.createNotificationChannel(NotificationHelper.channelFromJSON(context, jchannel)); Log.i("Imported folder channel=" + jchannel); } @@ -1016,7 +1012,7 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac String channelId = jchannel.getString("id"); nm.deleteNotificationChannel(channelId); - nm.createNotificationChannel(channelFromJSON(context, jchannel)); + nm.createNotificationChannel(NotificationHelper.channelFromJSON(context, jchannel)); Log.i("Imported contact channel=" + jchannel); } @@ -1130,65 +1126,6 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac } } - @RequiresApi(api = Build.VERSION_CODES.O) - private JSONObject channelToJSON(NotificationChannel channel) throws JSONException { - 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 - - return jchannel; - } - - @RequiresApi(api = Build.VERSION_CODES.O) - static NotificationChannel channelFromJSON(Context context, JSONObject jchannel) throws JSONException { - NotificationChannel channel = new NotificationChannel( - jchannel.getString("id"), - jchannel.getString("name"), - jchannel.getInt("importance")); - - String group = jchannel.optString("group"); - if (!TextUtils.isEmpty(group)) - channel.setGroup(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(context, uri); - if (ringtone != null) - channel.setSound(uri, Notification.AUDIO_ATTRIBUTES_DEFAULT); - } - - channel.enableLights(jchannel.getBoolean("light")); - channel.enableVibration(jchannel.getBoolean("vibrate")); - - return channel; - } - private void onGmail(Intent intent) { FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.replace(R.id.content_frame, new FragmentGmail()).addToBackStack("quick"); diff --git a/app/src/main/java/eu/faircode/email/Log.java b/app/src/main/java/eu/faircode/email/Log.java index 2f835ffb18..95a1317934 100644 --- a/app/src/main/java/eu/faircode/email/Log.java +++ b/app/src/main/java/eu/faircode/email/Log.java @@ -22,6 +22,8 @@ package eu.faircode.email; import android.app.ActivityManager; import android.app.ApplicationExitInfo; import android.app.Dialog; +import android.app.NotificationChannel; +import android.app.NotificationManager; import android.app.usage.UsageStatsManager; import android.content.Context; import android.content.DialogInterface; @@ -51,6 +53,7 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.FragmentManager; import androidx.preference.PreferenceManager; @@ -1140,6 +1143,8 @@ public class Log { attachLog(context, draft.id, 4); attachOperations(context, draft.id, 5); attachLogcat(context, draft.id, 6); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + attachNotificationInfo(context, draft.id, 7); EntityOperation.queue(context, draft, EntityOperation.ADD); @@ -1515,6 +1520,7 @@ public class Log { db.attachment().setDownloaded(attachment.id, size); } + private static void attachLog(Context context, long id, int sequence) throws IOException { DB db = DB.getInstance(context); @@ -1610,6 +1616,39 @@ public class Log { } } + @RequiresApi(api = Build.VERSION_CODES.O) + private static void attachNotificationInfo(Context context, long id, int sequence) throws IOException { + DB db = DB.getInstance(context); + + EntityAttachment attachment = new EntityAttachment(); + attachment.message = id; + attachment.sequence = sequence; + attachment.name = "channel.txt"; + attachment.type = "text/plain"; + attachment.disposition = Part.ATTACHMENT; + attachment.size = null; + attachment.progress = 0; + attachment.id = db.attachment().insertAttachment(attachment); + + long size = 0; + File file = attachment.getFile(context); + try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) { + NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + + for (NotificationChannel channel : nm.getNotificationChannels()) + try { + JSONObject jchannel = NotificationHelper.channelToJSON(channel); + size += write(os, jchannel.toString(2) + "\r\n\r\n"); + } catch (JSONException ex) { + size += write(os, ex.toString() + "\r\n"); + } + + size += write(os, "Importance none=0; min=1; low=2; default=3; high=4; max=5\r\n\r\n"); + } + + db.attachment().setDownloaded(attachment.id, size); + } + private static int write(OutputStream os, String text) throws IOException { byte[] bytes = text.getBytes(); os.write(bytes); diff --git a/app/src/main/java/eu/faircode/email/NotificationHelper.java b/app/src/main/java/eu/faircode/email/NotificationHelper.java new file mode 100644 index 0000000000..71676f5819 --- /dev/null +++ b/app/src/main/java/eu/faircode/email/NotificationHelper.java @@ -0,0 +1,95 @@ +package eu.faircode.email; + +/* + This file is part of FairEmail. + + FairEmail is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + FairEmail 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with FairEmail. If not, see . + + Copyright 2018-2020 by Marcel Bokhorst (M66B) +*/ + +import android.app.Notification; +import android.app.NotificationChannel; +import android.content.Context; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Build; +import android.text.TextUtils; + +import androidx.annotation.RequiresApi; + +import org.json.JSONException; +import org.json.JSONObject; + +class NotificationHelper { + @RequiresApi(api = Build.VERSION_CODES.O) + static JSONObject channelToJSON(NotificationChannel channel) throws JSONException { + 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 + + return jchannel; + } + + @RequiresApi(api = Build.VERSION_CODES.O) + static NotificationChannel channelFromJSON(Context context, JSONObject jchannel) throws JSONException { + NotificationChannel channel = new NotificationChannel( + jchannel.getString("id"), + jchannel.getString("name"), + jchannel.getInt("importance")); + + String group = jchannel.optString("group"); + if (!TextUtils.isEmpty(group)) + channel.setGroup(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(context, uri); + if (ringtone != null) + channel.setSound(uri, Notification.AUDIO_ATTRIBUTES_DEFAULT); + } + + channel.enableLights(jchannel.getBoolean("light")); + channel.enableVibration(jchannel.getBoolean("vibrate")); + + return channel; + } +}