diff options
10 files changed, 150 insertions, 31 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java index b101c20c0..6202f62da 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java @@ -4,6 +4,7 @@ import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.provider.Settings; +import android.util.Log; import android.view.MenuItem; import android.view.View; @@ -17,9 +18,11 @@ import androidx.preference.PreferenceFragmentCompat; import com.bytehamster.lib.preferencesearch.SearchPreferenceResult; import com.bytehamster.lib.preferencesearch.SearchPreferenceResultListener; +import com.google.android.material.snackbar.Snackbar; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.preferences.ThemeSwitcher; import de.danoeh.antennapod.databinding.SettingsActivityBinding; +import de.danoeh.antennapod.event.MessageEvent; import de.danoeh.antennapod.fragment.preferences.AutoDownloadPreferencesFragment; import de.danoeh.antennapod.fragment.preferences.ImportExportPreferencesFragment; import de.danoeh.antennapod.fragment.preferences.MainPreferencesFragment; @@ -29,6 +32,9 @@ import de.danoeh.antennapod.fragment.preferences.PlaybackPreferencesFragment; import de.danoeh.antennapod.fragment.preferences.synchronization.SynchronizationPreferencesFragment; import de.danoeh.antennapod.fragment.preferences.SwipePreferencesFragment; import de.danoeh.antennapod.fragment.preferences.UserInterfacePreferencesFragment; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; /** * PreferenceActivity for API 11+. In order to change the behavior of the preference UI, see @@ -162,4 +168,26 @@ public class PreferenceActivity extends AppCompatActivity implements SearchPrefe result.highlight(fragment); } } + + @Override + protected void onStart() { + super.onStart(); + EventBus.getDefault().register(this); + } + + @Override + protected void onStop() { + super.onStop(); + EventBus.getDefault().unregister(this); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMainThread(MessageEvent event) { + Log.d(FRAGMENT_TAG, "onEvent(" + event + ")"); + Snackbar s = Snackbar.make(binding.getRoot(), event.message, Snackbar.LENGTH_LONG); + if (event.action != null) { + s.setAction(event.actionText, v -> event.action.accept(this)); + } + s.show(); + } } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java index fe5eb369c..e3473937e 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java @@ -32,9 +32,11 @@ import android.widget.SeekBar; import androidx.annotation.Nullable; import androidx.interpolator.view.animation.FastOutSlowInInterpolator; import com.bumptech.glide.Glide; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import de.danoeh.antennapod.R; import de.danoeh.antennapod.dialog.MediaPlayerErrorDialog; import de.danoeh.antennapod.dialog.VariableSpeedDialog; +import de.danoeh.antennapod.event.MessageEvent; import de.danoeh.antennapod.event.playback.BufferUpdateEvent; import de.danoeh.antennapod.event.playback.PlaybackPositionEvent; import de.danoeh.antennapod.event.PlayerErrorEvent; @@ -85,7 +87,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. private boolean videoSurfaceCreated = false; private boolean destroyingDueToReload = false; private long lastScreenTap = 0; - private Handler videoControlsHider = new Handler(Looper.getMainLooper()); + private final Handler videoControlsHider = new Handler(Looper.getMainLooper()); private VideoplayerActivityBinding viewBinding; private PlaybackController controller; private boolean showTimeLeft = false; @@ -516,6 +518,17 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar. MediaPlayerErrorDialog.show(this, event); } + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMainThread(MessageEvent event) { + Log.d(TAG, "onEvent(" + event + ")"); + final MaterialAlertDialogBuilder errorDialog = new MaterialAlertDialogBuilder(this); + errorDialog.setMessage(event.message); + if (event.action != null) { + errorDialog.setPositiveButton(event.actionText, (dialog, which) -> event.action.accept(this)); + } + errorDialog.show(); + } + @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java index 1df1e02a2..7e9c3d093 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java @@ -1,12 +1,22 @@ package de.danoeh.antennapod.fragment; +import android.Manifest; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; import android.os.Bundle; +import android.provider.Settings; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Toast; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.appbar.MaterialToolbar; import androidx.fragment.app.Fragment; @@ -122,6 +132,23 @@ public class FeedSettingsFragment extends Fragment { return fragment; } + boolean notificationPermissionDenied = false; + private final ActivityResultLauncher<String> requestPermissionLauncher = + registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> { + if (isGranted) { + return; + } + if (notificationPermissionDenied) { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + Uri uri = Uri.fromParts("package", getContext().getPackageName(), null); + intent.setData(uri); + startActivity(intent); + return; + } + Toast.makeText(getContext(), R.string.notification_permission_denied, Toast.LENGTH_LONG).show(); + notificationPermissionDenied = true; + }); + @Override public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, Bundle state) { final RecyclerView view = super.onCreateRecyclerView(inflater, parent, state); @@ -466,6 +493,11 @@ public class FeedSettingsFragment extends Fragment { pref.setChecked(feedPreferences.getShowEpisodeNotification()); pref.setOnPreferenceChangeListener((preference, newValue) -> { + if (Build.VERSION.SDK_INT >= 33 && ContextCompat.checkSelfPermission(getContext(), + Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { + requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS); + return false; + } boolean checked = newValue == Boolean.TRUE; feedPreferences.setShowEpisodeNotification(checked); DBWriter.setFeedPreferences(feedPreferences); diff --git a/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java index 1a700a296..21b36bc49 100644 --- a/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java @@ -59,6 +59,7 @@ public class HomeFragment extends Fragment implements Toolbar.OnMenuItemClickLis public static final String TAG = "HomeFragment"; public static final String PREF_NAME = "PrefHomeFragment"; public static final String PREF_HIDDEN_SECTIONS = "PrefHomeSectionsString"; + public static final String PREF_DISABLE_NOTIFICATION_PERMISSION_NAG = "DisableNotificationPermissionNag"; private static final String KEY_UP_ARROW = "up_arrow"; private boolean displayUpArrow; @@ -95,7 +96,10 @@ public class HomeFragment extends Fragment implements Toolbar.OnMenuItemClickLis if (Build.VERSION.SDK_INT >= 33 && ContextCompat.checkSelfPermission(getContext(), Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { - addSection(new AllowNotificationsSection()); + SharedPreferences prefs = getContext().getSharedPreferences(HomeFragment.PREF_NAME, Context.MODE_PRIVATE); + if (!prefs.getBoolean(HomeFragment.PREF_DISABLE_NOTIFICATION_PERMISSION_NAG, false)) { + addSection(new AllowNotificationsSection()); + } } List<String> hiddenSections = getHiddenSections(getContext()); diff --git a/app/src/main/java/de/danoeh/antennapod/ui/home/sections/AllowNotificationsSection.java b/app/src/main/java/de/danoeh/antennapod/ui/home/sections/AllowNotificationsSection.java index b023a19bf..0a0d30485 100644 --- a/app/src/main/java/de/danoeh/antennapod/ui/home/sections/AllowNotificationsSection.java +++ b/app/src/main/java/de/danoeh/antennapod/ui/home/sections/AllowNotificationsSection.java @@ -1,6 +1,7 @@ package de.danoeh.antennapod.ui.home.sections; import android.Manifest; +import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Build; @@ -15,6 +16,7 @@ import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.databinding.HomeSectionNotificationBinding; @@ -29,6 +31,7 @@ public class AllowNotificationsSection extends Fragment { ((MainActivity) getActivity()).loadFragment(HomeFragment.TAG, null); } else { viewBinding.openSettingsButton.setVisibility(View.VISIBLE); + viewBinding.allowButton.setVisibility(View.GONE); Toast.makeText(getContext(), R.string.notification_permission_denied, Toast.LENGTH_LONG).show(); } }); @@ -49,6 +52,17 @@ public class AllowNotificationsSection extends Fragment { intent.setData(uri); startActivity(intent); }); + viewBinding.denyButton.setOnClickListener(v -> { + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getContext()); + builder.setMessage(R.string.notification_permission_deny_warning); + builder.setPositiveButton(R.string.deny_label, (dialog, which) -> { + getContext().getSharedPreferences(HomeFragment.PREF_NAME, Context.MODE_PRIVATE) + .edit().putBoolean(HomeFragment.PREF_DISABLE_NOTIFICATION_PERMISSION_NAG, true).apply(); + ((MainActivity) getActivity()).loadFragment(HomeFragment.TAG, null); + }); + builder.setNegativeButton(R.string.cancel_label, null); + builder.show(); + }); return viewBinding.getRoot(); } } diff --git a/app/src/main/res/layout/home_section_notification.xml b/app/src/main/res/layout/home_section_notification.xml index 7e2182176..4d250b5a8 100644 --- a/app/src/main/res/layout/home_section_notification.xml +++ b/app/src/main/res/layout/home_section_notification.xml @@ -24,23 +24,40 @@ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginBottom="16dp" + android:layout_margin="16dp" android:text="@string/notification_permission_text" /> - <Button - android:id="@+id/allowButton" - android:layout_width="wrap_content" + <LinearLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_gravity="right" - android:text="@android:string/ok" /> + android:orientation="horizontal"> - <Button - android:id="@+id/openSettingsButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="right" - android:visibility="gone" - android:text="@string/open_settings" /> + <Button + android:id="@+id/denyButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/deny_label" + style="@style/Widget.MaterialComponents.Button.TextButton" /> + + <View + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" /> + + <Button + android:id="@+id/openSettingsButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:visibility="gone" + android:text="@string/open_settings" /> + + <Button + android:id="@+id/allowButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@android:string/ok" /> + + </LinearLayout> </LinearLayout> diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/EpisodeDownloadWorker.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/EpisodeDownloadWorker.java index 62956894c..dcce26042 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/EpisodeDownloadWorker.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/EpisodeDownloadWorker.java @@ -129,11 +129,7 @@ public class EpisodeDownloadWorker extends Worker { downloader.call(); } catch (Exception e) { DBWriter.addDownloadStatus(downloader.getResult()); - if (EventBus.getDefault().hasSubscriberForEvent(MessageEvent.class)) { - sendMessage(request.getTitle(), false); - } else { - sendErrorNotification(); - } + sendErrorNotification(request.getTitle()); FileUtils.deleteQuietly(new File(downloader.getDownloadRequest().getDestination())); return Result.failure(); } @@ -176,11 +172,7 @@ public class EpisodeDownloadWorker extends Worker { || status.getReason() == DownloadError.ERROR_UNAUTHORIZED || status.getReason() == DownloadError.ERROR_IO_BLOCKED) { // Fail fast, these are probably unrecoverable - if (EventBus.getDefault().hasSubscriberForEvent(MessageEvent.class)) { - sendMessage(request.getTitle(), false); - } else { - sendErrorNotification(); - } + sendErrorNotification(request.getTitle()); FileUtils.deleteQuietly(new File(downloader.getDownloadRequest().getDestination())); return Result.failure(); } @@ -193,7 +185,7 @@ public class EpisodeDownloadWorker extends Worker { private Result retry3times() { if (isLastRunAttempt()) { - sendErrorNotification(); + sendErrorNotification(downloader.getDownloadRequest().getTitle()); return Result.failure(); } else { return Result.retry(); @@ -227,7 +219,12 @@ public class EpisodeDownloadWorker extends Worker { PendingIntent.FLAG_UPDATE_CURRENT | (Build.VERSION.SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0)); } - private void sendErrorNotification() { + private void sendErrorNotification(String title) { + if (EventBus.getDefault().hasSubscriberForEvent(MessageEvent.class)) { + sendMessage(title, false); + return; + } + NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), NotificationUtils.CHANNEL_ID_DOWNLOAD_ERROR); builder.setTicker(getApplicationContext().getString(R.string.download_report_title)) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index c82d6f975..77ac2bccc 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -562,6 +562,12 @@ public class PlaybackService extends MediaBrowserServiceCompat { @SuppressLint("LaunchActivityFromNotification") private void displayStreamingNotAllowedNotification(Intent originalIntent) { + if (EventBus.getDefault().hasSubscriberForEvent(MessageEvent.class)) { + EventBus.getDefault().post(new MessageEvent( + getString(R.string.confirm_mobile_streaming_notification_message))); + return; + } + Intent intentAllowThisTime = new Intent(originalIntent); intentAllowThisTime.setAction(PlaybackServiceInterface.EXTRA_ALLOW_STREAM_THIS_TIME); intentAllowThisTime.putExtra(PlaybackServiceInterface.EXTRA_ALLOW_STREAM_THIS_TIME, true); diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java b/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java index 7fe0c5e46..dc6b7ff80 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java @@ -22,6 +22,7 @@ import androidx.work.WorkerParameters; import de.danoeh.antennapod.core.util.download.FeedUpdateManager; import de.danoeh.antennapod.event.FeedUpdateRunningEvent; +import de.danoeh.antennapod.event.MessageEvent; import de.danoeh.antennapod.model.feed.FeedItemFilter; import de.danoeh.antennapod.model.feed.SortOrder; import org.apache.commons.lang3.StringUtils; @@ -298,13 +299,18 @@ public class SyncService extends Worker { } private void updateErrorNotification(Exception exception) { + Log.d(TAG, "Posting sync error notification"); + final String description = getApplicationContext().getString(R.string.gpodnetsync_error_descr) + + exception.getMessage(); + if (!UserPreferences.gpodnetNotificationsEnabled()) { Log.d(TAG, "Skipping sync error notification because of user setting"); return; } - Log.d(TAG, "Posting sync error notification"); - final String description = getApplicationContext().getString(R.string.gpodnetsync_error_descr) - + exception.getMessage(); + if (EventBus.getDefault().hasSubscriberForEvent(MessageEvent.class)) { + EventBus.getDefault().post(new MessageEvent(description)); + return; + } Intent intent = getApplicationContext().getPackageManager().getLaunchIntentForPackage( getApplicationContext().getPackageName()); diff --git a/ui/i18n/src/main/res/values/strings.xml b/ui/i18n/src/main/res/values/strings.xml index c585a6616..7992189ef 100644 --- a/ui/i18n/src/main/res/values/strings.xml +++ b/ui/i18n/src/main/res/values/strings.xml @@ -61,8 +61,10 @@ <string name="home_downloads_title">Manage downloads</string> <string name="home_welcome_title">Welcome to AntennaPod!</string> <string name="home_welcome_text">You are not subscribed to any podcasts yet. Open the side menu to add a podcast.</string> - <string name="notification_permission_text">AntennaPod needs your permission to show notifications while downloading episodes.</string> + <string name="notification_permission_text">AntennaPod needs your permission to show notifications. By default, AntennaPod only shows notifications while something is being downloaded or when something goes wrong.</string> <string name="notification_permission_denied">You denied the permission.</string> + <string name="notification_permission_deny_warning">If you disable notifications and something goes wrong, you might be unable to find out why it went wrong.</string> + <string name="deny_label">Deny</string> <string name="open_settings">Open settings</string> <string name="configure_home">Configure Home Screen</string> |