From 677b6b5906e7087a212c38bf0f6779125ee0d8d1 Mon Sep 17 00:00:00 2001 From: Roman Tsisyk Date: Tue, 29 Aug 2023 11:02:05 +0300 Subject: [PATCH] [android] Remove legacy notifications implementation Use NotificationManagerCompat from the compat library Signed-off-by: Roman Tsisyk --- android/build.gradle | 1 + android/res/values/colors.xml | 2 +- android/src/app/organicmaps/MwmActivity.java | 44 +++++- .../src/app/organicmaps/MwmApplication.java | 15 +-- .../NotificationChannelFactory.java | 17 --- .../NotificationChannelProvider.java | 11 -- .../app/organicmaps/background/Notifier.java | 127 ------------------ ...OreoCompatNotificationChannelProvider.java | 43 ------ .../StubNotificationChannelProvider.java | 47 ------- .../downloader/DownloaderNotifier.java | 104 ++++++++++++++ .../downloader/OnmapDownloader.java | 11 +- ...tryFailedDownloadConfirmationListener.java | 5 +- 12 files changed, 158 insertions(+), 269 deletions(-) delete mode 100644 android/src/app/organicmaps/background/NotificationChannelFactory.java delete mode 100644 android/src/app/organicmaps/background/NotificationChannelProvider.java delete mode 100644 android/src/app/organicmaps/background/Notifier.java delete mode 100644 android/src/app/organicmaps/background/OreoCompatNotificationChannelProvider.java delete mode 100644 android/src/app/organicmaps/background/StubNotificationChannelProvider.java create mode 100644 android/src/app/organicmaps/downloader/DownloaderNotifier.java diff --git a/android/build.gradle b/android/build.gradle index 6cb3ae9771..93f7b0fcd8 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -86,6 +86,7 @@ dependencies { // > A failure occurred while executing com.android.build.gradle.internal.tasks.CheckDuplicatesRunnable // We don't use Kotlin, but some dependencies are actively using it. implementation(platform('org.jetbrains.kotlin:kotlin-bom:1.8.21')) + implementation 'androidx.core:core:1.10.1' implementation 'androidx.annotation:annotation:1.6.0' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' diff --git a/android/res/values/colors.xml b/android/res/values/colors.xml index a98809f005..5e547038c6 100644 --- a/android/res/values/colors.xml +++ b/android/res/values/colors.xml @@ -125,7 +125,7 @@ #FFF2F6F6 #3D000000 - #82E510 + @color/bg_primary #FFC800 #FF9600 diff --git a/android/src/app/organicmaps/MwmActivity.java b/android/src/app/organicmaps/MwmActivity.java index 55b5932c4b..b6a7c023f1 100644 --- a/android/src/app/organicmaps/MwmActivity.java +++ b/android/src/app/organicmaps/MwmActivity.java @@ -8,6 +8,7 @@ import android.content.Context; import android.content.Intent; import android.location.Location; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.text.TextUtils; import android.view.KeyEvent; @@ -37,7 +38,7 @@ import androidx.lifecycle.ViewModelProvider; import app.organicmaps.Framework.PlacePageActivationListener; import app.organicmaps.api.Const; import app.organicmaps.background.AppBackgroundTracker; -import app.organicmaps.background.Notifier; +import app.organicmaps.downloader.DownloaderNotifier; import app.organicmaps.base.BaseMwmFragmentActivity; import app.organicmaps.base.CustomNavigateUpListener; import app.organicmaps.base.NoConnectionListener; @@ -110,6 +111,7 @@ import java.util.Stack; import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION; +import static android.Manifest.permission.POST_NOTIFICATIONS; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static app.organicmaps.location.LocationState.LOCATION_TAG; @@ -206,6 +208,10 @@ public class MwmActivity extends BaseMwmFragmentActivity @NonNull private ActivityResultLauncher mLocationPermissionRequest; + @SuppressWarnings("NotNullFieldNotInitialized") + @NonNull + private ActivityResultLauncher mPostNotificationPermissionRequest; + @SuppressWarnings("NotNullFieldNotInitialized") @NonNull private ActivityResultLauncher mLocationResolutionRequest; @@ -411,6 +417,8 @@ public class MwmActivity extends BaseMwmFragmentActivity this::onLocationPermissionsResult); mLocationResolutionRequest = registerForActivityResult(new ActivityResultContracts.StartIntentSenderForResult(), this::onLocationResolutionResult); + mPostNotificationPermissionRequest = registerForActivityResult(new ActivityResultContracts.RequestPermission(), + this::onPostNotificationPermissionResult); boolean isConsumed = savedInstanceState == null && processIntent(getIntent()); boolean isFirstLaunch = Counters.isFirstLaunch(this); @@ -943,8 +951,7 @@ public class MwmActivity extends BaseMwmFragmentActivity if (intent == null) return false; - final Notifier notifier = Notifier.from(getApplication()); - notifier.processNotificationExtras(intent); + DownloaderNotifier.processNotificationExtras(getApplicationContext(), intent); if (intent.hasExtra(EXTRA_TASK)) { @@ -1087,6 +1094,8 @@ public class MwmActivity extends BaseMwmFragmentActivity mLocationPermissionRequest = null; mLocationResolutionRequest.unregister(); mLocationResolutionRequest = null; + mPostNotificationPermissionRequest.unregister(); + mPostNotificationPermissionRequest = null; } @Override @@ -1765,6 +1774,22 @@ public class MwmActivity extends BaseMwmFragmentActivity }); } + /** + * Request POST_NOTIFICATIONS permission. + */ + public void requestPostNotificationsPermission() + { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || + ActivityCompat.checkSelfPermission(this, POST_NOTIFICATIONS) == PERMISSION_GRANTED) + { + Logger.i(TAG, "Permissions POST_NOTIFICATIONS is granted"); + return; + } + + Logger.i(TAG, "Requesting POST_NOTIFICATIONS permission"); + mPostNotificationPermissionRequest.launch(POST_NOTIFICATIONS); + } + /** * Resume location services when entering the foreground. */ @@ -1861,6 +1886,19 @@ public class MwmActivity extends BaseMwmFragmentActivity .show(); } + /** + * Called on the result of the POST_NOTIFICATIONS request. + * @param granted true if permission has been granted. + */ + @UiThread + private void onPostNotificationPermissionResult(boolean granted) + { + if (granted) + Logger.i(TAG, "Permission POST_NOTIFICATIONS has been granted"); + else + Logger.w(TAG, "Permission POST_NOTIFICATIONS has been refused"); + } + /** * Called by GoogleFusedLocationProvider to request to GPS and/or Wi-Fi. * @param pendingIntent an intent to launch. diff --git a/android/src/app/organicmaps/MwmApplication.java b/android/src/app/organicmaps/MwmApplication.java index a4860b41a5..47e3870fe9 100644 --- a/android/src/app/organicmaps/MwmApplication.java +++ b/android/src/app/organicmaps/MwmApplication.java @@ -8,9 +8,7 @@ import android.os.Message; import androidx.annotation.NonNull; import app.organicmaps.background.AppBackgroundTracker; -import app.organicmaps.background.NotificationChannelFactory; -import app.organicmaps.background.NotificationChannelProvider; -import app.organicmaps.background.Notifier; +import app.organicmaps.downloader.DownloaderNotifier; import app.organicmaps.base.MediaPlayerWrapper; import app.organicmaps.bookmarks.data.BookmarkManager; import app.organicmaps.downloader.CountryItem; @@ -116,7 +114,7 @@ public class MwmApplication extends Application implements AppBackgroundTracker. ConnectionState.INSTANCE.initialize(this); CrashlyticsUtils.INSTANCE.initialize(this); - initNotificationChannels(); + DownloaderNotifier.createNotificationChannel(this); mBackgroundTracker = new AppBackgroundTracker(this); mSubwayManager = new SubwayManager(this); @@ -125,12 +123,6 @@ public class MwmApplication extends Application implements AppBackgroundTracker. mPlayer = new MediaPlayerWrapper(this); } - private void initNotificationChannels() - { - NotificationChannelProvider channelProvider = NotificationChannelFactory.createProvider(this); - channelProvider.setDownloadingChannel(); - } - /** * Initialize native core of application: platform and framework. * @@ -281,13 +273,12 @@ public class MwmApplication extends Application implements AppBackgroundTracker. @Override public void onStatusChanged(List data) { - Notifier notifier = Notifier.from(MwmApplication.this); for (MapManager.StorageCallbackData item : data) if (item.isLeafNode && item.newStatus == CountryItem.STATUS_FAILED) { if (MapManager.nativeIsAutoretryFailed()) { - notifier.notifyDownloadFailed(item.countryId, MapManager.nativeGetName(item.countryId)); + DownloaderNotifier.notifyDownloadFailed(MwmApplication.this, item.countryId); } return; diff --git a/android/src/app/organicmaps/background/NotificationChannelFactory.java b/android/src/app/organicmaps/background/NotificationChannelFactory.java deleted file mode 100644 index 12b66f03f9..0000000000 --- a/android/src/app/organicmaps/background/NotificationChannelFactory.java +++ /dev/null @@ -1,17 +0,0 @@ -package app.organicmaps.background; - -import android.app.Application; - -import androidx.annotation.NonNull; - -import app.organicmaps.util.Utils; - -public class NotificationChannelFactory -{ - @NonNull - public static NotificationChannelProvider createProvider(@NonNull Application app) - { - return Utils.isOreoOrLater() ? new OreoCompatNotificationChannelProvider(app) - : new StubNotificationChannelProvider(app); - } -} diff --git a/android/src/app/organicmaps/background/NotificationChannelProvider.java b/android/src/app/organicmaps/background/NotificationChannelProvider.java deleted file mode 100644 index 591314f7da..0000000000 --- a/android/src/app/organicmaps/background/NotificationChannelProvider.java +++ /dev/null @@ -1,11 +0,0 @@ -package app.organicmaps.background; - -import androidx.annotation.NonNull; - -public interface NotificationChannelProvider -{ - @NonNull - String getDownloadingChannel(); - - void setDownloadingChannel(); -} diff --git a/android/src/app/organicmaps/background/Notifier.java b/android/src/app/organicmaps/background/Notifier.java deleted file mode 100644 index a1f388bb1b..0000000000 --- a/android/src/app/organicmaps/background/Notifier.java +++ /dev/null @@ -1,127 +0,0 @@ -package app.organicmaps.background; - -import android.app.Application; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.os.Build; - -import androidx.annotation.IntDef; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.app.NotificationCompat; -import androidx.core.content.ContextCompat; - -import app.organicmaps.MwmActivity; -import app.organicmaps.R; -import app.organicmaps.util.StringUtils; -import app.organicmaps.util.UiUtils; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -public final class Notifier -{ - private static final String EXTRA_CANCEL_NOTIFICATION = "extra_cancel_notification"; - private static final String EXTRA_NOTIFICATION_CLICKED = "extra_notification_clicked"; - - public static final int ID_NONE = 0; - public static final int ID_DOWNLOAD_FAILED = 1; - public static final int ID_IS_NOT_AUTHENTICATED = 2; - public static final int ID_LEAVE_REVIEW = 3; - @NonNull - private final Application mContext; - - @Retention(RetentionPolicy.SOURCE) - @IntDef({ ID_NONE, ID_DOWNLOAD_FAILED, ID_IS_NOT_AUTHENTICATED, ID_LEAVE_REVIEW }) - public @interface NotificationId - { - } - - private Notifier(@NonNull Application context) - { - mContext = context; - } - - public void notifyDownloadFailed(@Nullable String id, @Nullable String name) - { - String title = mContext.getString(R.string.app_name); - String content = mContext.getString(R.string.download_country_failed, name); - - Intent intent = MwmActivity.createShowMapIntent(mContext, id) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - final int flags = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) - ? PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_UPDATE_CURRENT; - PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, flags); - - String channel = NotificationChannelFactory.createProvider(mContext).getDownloadingChannel(); - placeNotification(title, content, pi, ID_DOWNLOAD_FAILED, channel); - } - - public void cancelNotification(@NotificationId int id) - { - if (id == ID_NONE) - return; - - getNotificationManager().cancel(id); - } - - public void processNotificationExtras(@Nullable Intent intent) - { - if (intent == null) - return; - - if (intent.hasExtra(Notifier.EXTRA_CANCEL_NOTIFICATION)) - { - @Notifier.NotificationId - int notificationId = intent.getIntExtra(Notifier.EXTRA_CANCEL_NOTIFICATION, Notifier.ID_NONE); - cancelNotification(notificationId); - } - } - - private void placeNotification(String title, String content, PendingIntent pendingIntent, - int notificationId, @NonNull String channel) - { - final Notification notification = getBuilder(title, content, pendingIntent, channel).build(); - - getNotificationManager().notify(notificationId, notification); - } - - @NonNull - private NotificationCompat.Builder getBuilder(String title, String content, - PendingIntent pendingIntent, @NonNull String channel) - { - - return new NotificationCompat.Builder(mContext, channel) - .setAutoCancel(true) - .setSmallIcon(R.drawable.ic_notification) - .setColor(ContextCompat.getColor(mContext, R.color.notification)) - .setContentTitle(title) - .setContentText(content) - .setTicker(getTicker(title, content)) - .setContentIntent(pendingIntent); - } - - @NonNull - private CharSequence getTicker(String title, String content) - { - int templateResId = StringUtils.isRtl() ? R.string.notification_ticker_rtl - : R.string.notification_ticker_ltr; - return mContext.getString(templateResId, title, content); - } - - @SuppressWarnings("ConstantConditions") - @NonNull - private NotificationManager getNotificationManager() - { - return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); - } - - @NonNull - public static Notifier from(Application application) - { - return new Notifier(application); - } -} diff --git a/android/src/app/organicmaps/background/OreoCompatNotificationChannelProvider.java b/android/src/app/organicmaps/background/OreoCompatNotificationChannelProvider.java deleted file mode 100644 index 701585e96a..0000000000 --- a/android/src/app/organicmaps/background/OreoCompatNotificationChannelProvider.java +++ /dev/null @@ -1,43 +0,0 @@ -package app.organicmaps.background; - -import android.annotation.TargetApi; -import android.app.Application; -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.os.Build; - -import androidx.annotation.NonNull; - -import app.organicmaps.R; - -import java.util.Objects; - -@TargetApi(Build.VERSION_CODES.O) -public class OreoCompatNotificationChannelProvider extends StubNotificationChannelProvider -{ - private static final String DOWNLOADING_NOTIFICATION_CHANNEL = "downloading_notification_channel"; - - OreoCompatNotificationChannelProvider(@NonNull Application app) - { - super(app, DOWNLOADING_NOTIFICATION_CHANNEL); - } - - private void setChannelInternal(@NonNull String id, @NonNull String name) - { - NotificationManager notificationManager = getApplication().getSystemService(NotificationManager.class); - NotificationChannel channel = Objects.requireNonNull(notificationManager) - .getNotificationChannel(id); - if (channel == null) - channel = new NotificationChannel(id, name, NotificationManager.IMPORTANCE_DEFAULT); - else - channel.setName(name); - notificationManager.createNotificationChannel(channel); - } - - @Override - public void setDownloadingChannel() - { - String name = getApplication().getString(R.string.notification_channel_downloader); - setChannelInternal(getDownloadingChannel(), name); - } -} diff --git a/android/src/app/organicmaps/background/StubNotificationChannelProvider.java b/android/src/app/organicmaps/background/StubNotificationChannelProvider.java deleted file mode 100644 index 0bea3320ac..0000000000 --- a/android/src/app/organicmaps/background/StubNotificationChannelProvider.java +++ /dev/null @@ -1,47 +0,0 @@ -package app.organicmaps.background; - -import android.app.Application; - -import androidx.annotation.NonNull; - -public class StubNotificationChannelProvider implements NotificationChannelProvider -{ - private static final String DEFAULT_NOTIFICATION_CHANNEL = "default_notification_channel"; - - @NonNull - private final Application mApplication; - - @NonNull - private final String mDownloadingChannel; - - - StubNotificationChannelProvider(@NonNull Application context, @NonNull String downloadingChannel) - { - mApplication = context; - mDownloadingChannel = downloadingChannel; - } - - StubNotificationChannelProvider(@NonNull Application context) - { - this(context, DEFAULT_NOTIFICATION_CHANNEL); - } - - @NonNull - @Override - public String getDownloadingChannel() - { - return mDownloadingChannel; - } - - @Override - public void setDownloadingChannel() - { - /*Do nothing */ - } - - @NonNull - protected Application getApplication() - { - return mApplication; - } -} diff --git a/android/src/app/organicmaps/downloader/DownloaderNotifier.java b/android/src/app/organicmaps/downloader/DownloaderNotifier.java new file mode 100644 index 0000000000..a0b2841278 --- /dev/null +++ b/android/src/app/organicmaps/downloader/DownloaderNotifier.java @@ -0,0 +1,104 @@ +package app.organicmaps.downloader; + +import static android.Manifest.permission.POST_NOTIFICATIONS; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + +import android.app.Notification; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.Build; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.core.app.NotificationChannelCompat; +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; +import androidx.core.content.ContextCompat; + +import app.organicmaps.MwmActivity; +import app.organicmaps.R; +import app.organicmaps.util.StringUtils; +import app.organicmaps.util.log.Logger; + +public abstract class DownloaderNotifier +{ + private static final String TAG = DownloaderNotifier.class.getSimpleName(); + + private static final String CHANNEL_ID = "downloader"; + + private static final String EXTRA_CANCEL_NOTIFICATION = "extra_cancel_downloader_notification"; + private static final int NOTIFICATION_ID = 1; + + public static void createNotificationChannel(@NonNull Context context) + { + final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); + final NotificationChannelCompat channel = new NotificationChannelCompat.Builder(CHANNEL_ID, + NotificationManagerCompat.IMPORTANCE_DEFAULT) + .setName(context.getString(R.string.notification_channel_downloader)) + .setShowBadge(true) + .build(); + notificationManager.createNotificationChannel(channel); + } + + public static void notifyDownloadFailed(@NonNull Context context, @Nullable String countryId) + { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && + ContextCompat.checkSelfPermission(context, POST_NOTIFICATIONS) != PERMISSION_GRANTED) + { + Logger.w(TAG, "Permission POST_NOTIFICATIONS is not granted, skipping notification"); + return; + } + + final String title = context.getString(R.string.app_name); + final String countryName = MapManager.nativeGetName(countryId); + final String content = context.getString(R.string.download_country_failed, countryName); + + final int FLAG_IMMUTABLE = Build.VERSION.SDK_INT < Build.VERSION_CODES.M ? 0 : PendingIntent.FLAG_IMMUTABLE; + final Intent contentIntent = MwmActivity.createShowMapIntent(context, countryId); + contentIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + final PendingIntent contentPendingIntent = PendingIntent.getActivity(context, 0, contentIntent, + PendingIntent.FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE); + + final Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID) + .setAutoCancel(true) + .setCategory(NotificationCompat.CATEGORY_ERROR) + .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + .setSmallIcon(R.drawable.ic_notification) + .setColor(ContextCompat.getColor(context, R.color.notification)) + .setContentTitle(title) + .setContentText(content) + .setShowWhen(true) + .setTicker(getTicker(context, title, content)) + .setContentIntent(contentPendingIntent) + .build(); + + Logger.i(TAG, "Notifying about failed map download"); + final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); + notificationManager.notify(NOTIFICATION_ID, notification); + } + + static void cancelNotification(@NonNull Context context) + { + Logger.i(TAG, "Cancelling notification about failed map download"); + final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); + notificationManager.cancel(NOTIFICATION_ID); + } + + public static void processNotificationExtras(@NonNull Context context, @Nullable Intent intent) + { + if (!intent.hasExtra(EXTRA_CANCEL_NOTIFICATION)) + return; + + cancelNotification(context); + } + + @NonNull + private static CharSequence getTicker(@NonNull Context context, @NonNull String title, @NonNull String content) + { + @StringRes final int templateResId = StringUtils.isRtl() ? R.string.notification_ticker_rtl + : R.string.notification_ticker_ltr; + return context.getString(templateResId, title, content); + } +} diff --git a/android/src/app/organicmaps/downloader/OnmapDownloader.java b/android/src/app/organicmaps/downloader/OnmapDownloader.java index 5de160e23a..da12317cba 100644 --- a/android/src/app/organicmaps/downloader/OnmapDownloader.java +++ b/android/src/app/organicmaps/downloader/OnmapDownloader.java @@ -12,7 +12,6 @@ import androidx.annotation.Nullable; import androidx.core.view.ViewCompat; import app.organicmaps.MwmActivity; import app.organicmaps.R; -import app.organicmaps.background.Notifier; import app.organicmaps.location.LocationHelper; import app.organicmaps.routing.RoutingController; import app.organicmaps.widget.WheelProgressView; @@ -169,6 +168,7 @@ public class OnmapDownloader implements MwmActivity.LeftAnimationTrackListener MapManager.nativeHasSpaceToDownloadCountry(country)) { MapManager.nativeDownload(mCurrentCountry.id); + mActivity.requestPostNotificationsPermission(); } } } @@ -209,19 +209,22 @@ public class OnmapDownloader implements MwmActivity.LeftAnimationTrackListener setAutodownloadLocked(true); } }); - final Notifier notifier = Notifier.from(activity.getApplication()); - mButton.setOnClickListener(v -> MapManager.warnOn3g(mActivity, mCurrentCountry == null ? null : mCurrentCountry.id, () -> { + mButton.setOnClickListener(v -> MapManager.warnOn3g(mActivity, mCurrentCountry == null ? null : + mCurrentCountry.id, () -> { if (mCurrentCountry == null) return; boolean retry = (mCurrentCountry.status == CountryItem.STATUS_FAILED); if (retry) { - notifier.cancelNotification(Notifier.ID_DOWNLOAD_FAILED); + DownloaderNotifier.cancelNotification(mActivity.getApplicationContext()); MapManager.nativeRetry(mCurrentCountry.id); } else + { MapManager.nativeDownload(mCurrentCountry.id); + mActivity.requestPostNotificationsPermission(); + } })); ViewCompat.setOnApplyWindowInsetsListener(mFrame, (view, windowInsets) -> { diff --git a/android/src/app/organicmaps/downloader/RetryFailedDownloadConfirmationListener.java b/android/src/app/organicmaps/downloader/RetryFailedDownloadConfirmationListener.java index 8ba3b209cb..ecc252d2ec 100644 --- a/android/src/app/organicmaps/downloader/RetryFailedDownloadConfirmationListener.java +++ b/android/src/app/organicmaps/downloader/RetryFailedDownloadConfirmationListener.java @@ -4,8 +4,6 @@ import android.app.Application; import androidx.annotation.NonNull; -import app.organicmaps.background.Notifier; - public class RetryFailedDownloadConfirmationListener implements Runnable { @NonNull @@ -19,7 +17,6 @@ public class RetryFailedDownloadConfirmationListener implements Runnable @Override public void run() { - final Notifier notifier = Notifier.from(mApplication); - notifier.cancelNotification(Notifier.ID_DOWNLOAD_FAILED); + DownloaderNotifier.cancelNotification(mApplication); } }