Сейчас для того чтобы опубликовать обновление приложения в PlayМаркет, требуется API не ниже 26. Иначе выдает ошибку:
Целевой уровень API для вашего приложения – 25. Чтобы обеспечить необходимую производительность и безопасность, целевой уровень API должен быть не ниже 26. Установите для своего приложения целевой уровень API не менее 26.
Если в build.gradle я изменяю targetSdkVersion
с 25
на 27
то приложение компилируется и заливается в маркет без ошибок, но на устройствах с Android 8.0 получаю краш приложения, связанный с notification, который отображается в шторке андроида (приложение плеер). Какие изменения с этим notification я должен произвести, чтобы всё работало стабильно?
build.gradle:
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.test.app"
minSdkVersion 16
//noinspection ExpiringTargetSdkVersion
targetSdkVersion 27
versionCode 2
versionName "2"
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
}
signingConfigs {
}
buildTypes {
debug {
minifyEnabled false
//shrinkResources true
//useProguard false
proguardFiles getDefaultProguardFile ('proguard-android.txt'), 'proguard-rules.pro'
}
release {
//signingConfig signingConfigs.release
minifyEnabled false
shrinkResources false
proguardFiles getDefaultProguardFile ('proguard-android.txt'), 'proguard-rules.pro'
}
}
dexOptions {
jumboMode true
}
configurations {
all{
exclude group: 'commons-logging', module: 'commons-logging'
exclude group: 'org.apache.httpcomponents'
}
}
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/NOTICE'
exclude 'org/apache/http/version.properties'
exclude 'org/apache/http/client/version.properties'
}
}
dependencies {
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support:support-vector-drawable:28.0.0'
implementation fileTree(include: ['*.jar'], dir: 'libs')
//implementation files('libs/http-core-4.1.jar')
//implementation files('libs/httpclient-4.0.3.jar')
//implementation files('libs/httpclient-cache-4.2.5.jar')
//implementation files('libs/httpmime-4.2.5.jar')
implementation 'com.github.claucookie.miniequalizer:library:1.0.0'
implementation 'com.rm:rmswitch:1.2.2'
implementation 'com.github.d-max:spots-dialog:0.7@aar'
implementation 'com.android.support:multidex:1.0.3'
implementation group: 'org.jsoup', name: 'jsoup', version: '1.11.2'
implementation 'com.github.javiersantos:MaterialStyledDialogs:2.1'
implementation 'com.makeramen:roundedimageview:2.3.0'
implementation 'com.github.bumptech.glide:glide:3.7.0'
implementation 'de.hdodenhof:circleimageview:1.3.0'
implementation ('com.mikepenz.materialdrawer:library:2.9.2@aar')
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:cardview-v7:28.0.0'
// implementation 'com.android.support.constraint:constraint-layout:1.1.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.android.support:palette-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.google.android.exoplayer:exoplayer:r1.5.16'
implementation 'com.squareup.okhttp:okhttp:2.7.2'
implementation 'org.ini4j:ini4j:0.5.4'
implementation 'com.squareup:otto:1.3.8'
implementation 'com.google.code.gson:gson:2.8.2'
implementation 'com.sothree.slidinguppanel:library:3.1.1'
implementation 'org.quuux.feller:feller:0.1'
implementation 'com.android.volley:volley:1.0.0'
implementation 'com.squareup.picasso:picasso:2.5.2'
//Custom Toasts
implementation 'com.muddzdev:styleabletoast:2.1.3'
// ButterKnife (for sample code brevity)
implementation 'com.jakewharton:butterknife:8.8.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
implementation 'com.google.firebase:firebase-firestore:11.8.0'
// Android architecture components
implementation 'android.arch.lifecycle:runtime:1.1.1'
implementation 'android.arch.lifecycle:extensions:1.1.1'
annotationProcessor 'android.arch.lifecycle:compiler:1.1.1'
// Check for v11.4.2 or higher
implementation 'com.google.firebase:firebase-core:11.8.0'
// Add dependency
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.5'
// Google Services
implementation 'com.google.android.gms:play-services-auth:11.8.0'
implementation 'com.google.android.gms:play-services-ads:11.8.0'
implementation 'com.google.android.gms:play-services-appinvite:11.8.0'
// Firebase Google
implementation 'com.google.firebase:firebase-ads:11.8.0'
implementation 'com.google.firebase:firebase-analytics:11.8.0'
implementation 'com.google.firebase:firebase-database:11.8.0'
implementation 'com.google.firebase:firebase-storage:11.8.0'
implementation 'com.google.firebase:firebase-auth:11.8.0'
implementation 'com.google.firebase:firebase-config:11.8.0'
implementation 'com.google.firebase:firebase-messaging:11.8.0'
implementation 'com.google.firebase:firebase-appindexing:11.8.0'
implementation 'com.google.firebase:firebase-crash:11.8.0'
implementation 'com.firebaseui:firebase-ui-database:1.0.0'
implementation 'com.github.wrdlbrnft:sorted-list-adapter:0.2.0.19'
implementation 'com.android.support:gridlayout-v7:28.0.0'
// android support-v7 27.1.1
}
apply plugin: 'com.google.gms.google-services'
логи ошибки:
2018-11-14 17:14:55.375 13641-13641/com.test.app E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.test.app, PID: 13641
android.app.RemoteServiceException: Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notification: Notification(channel=null pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x42 color=0x00000000 category=transport actions=2 vis=PUBLIC)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1768)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
2018-11-14 17:14:55.564 13641-13641/com.test.app E/UncaughtException: android.app.RemoteServiceException: Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notification: Notification(channel=null pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x42 color=0x00000000 category=transport actions=2 vis=PUBLIC)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1768)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
PlaybackNotification.java:
public class PlaybackNotification {
public static Notification getInstance(final Context context, final Bitmap bitmap, final MediaSession mediaSession) {
final Notification.Builder builder = new Notification.Builder(context);
final Streamer stream = Streamer.getInstance();
final Station station = stream.getStation();
final StreamMetaData metadata = stream.getLastMetaData();
String text = metadata!= null ? metadata.getTitle() : null;
if (TextUtils.isEmpty(text))
text = station.getNetwork();
final int playbackIcon = stream.isPlaying() ? R.mipmap.ic_player_pause : R.mipmap.ic_player_play;
final String playbackText = context.getString(stream.isPlaying() ? R.string.action_pause : R.string.action_play);
final Intent playbackIntent = new Intent(context, PlaybackService.class);
playbackIntent.setAction(PlaybackService.ACTION_TOGGLE_PLAYBACK);
final Intent stopIntent = new Intent(context, PlaybackService.class);
stopIntent.setAction(PlaybackService.ACTION_STOP_PLAYBACK);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
final PlaybackState.Builder stateBuilder = new PlaybackState.Builder()
.setState(PlaybackState.STATE_PLAYING, 0, 1)
.setActions((stream.isPlaying() ? PlaybackState.ACTION_PAUSE : PlaybackState.ACTION_PLAY) | PlaybackState.ACTION_STOP);
builder.setAutoCancel(false);
builder.setOngoing(true);
builder.setSmallIcon(R.drawable.ic_action_ui_radio);
if (bitmap != null)
builder.setLargeIcon(bitmap);
builder.setContentTitle(station.getName()
.replace(" ᵗᵒᵖ 1. ","")
.replace(" ᵗᵒᵖ 2. ","")
.replace(" ᵗᵒᵖ 3. ","")
.replace(" ᵗᵒᵖ 4. ",""));
builder.setContentText(text);
mediaSession.setPlaybackState(stateBuilder.build());
final MediaMetadata mediaMetadata = new MediaMetadata.Builder()
.putBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON, bitmap)
.putBitmap(MediaMetadata.METADATA_KEY_ART, bitmap)
.putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE, text)
.putString(MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE, station.getName())
.putString(MediaMetadata.METADATA_KEY_TITLE, text)
.putString(MediaMetadata.METADATA_KEY_ARTIST, station.getName())
.build();
mediaSession.setMetadata(mediaMetadata);
builder.setVisibility(Notification.VISIBILITY_PUBLIC);
final Notification.Action play = new Notification.Action.Builder(playbackIcon, playbackText, PendingIntent.getService(context, 0, playbackIntent, 0)).build();
builder.addAction(play);
final Notification.Action stop = new Notification.Action.Builder(R.mipmap.ic_stop, context.getString(R.string.stop), PendingIntent.getService(context, 0, stopIntent, 0)).build();
builder.addAction(stop);
builder.setStyle(new Notification.MediaStyle().setShowActionsInCompactView(0, 1).setMediaSession(mediaSession.getSessionToken()));
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN){
builder.addAction(playbackIcon, playbackText, PendingIntent.getService(context, 0, playbackIntent, 0));
builder.addAction(R.mipmap.ic_stop, context.getString(R.string.stop), PendingIntent.getService(context, 0, stopIntent, 0));
}
final Intent intent = new Intent(context, AllStationActivity.class);
builder.setContentIntent(PendingIntent.getActivity(context, 0, intent, 0));
return builder.getNotification();
}
}
PlaybackService.java:
public class PlaybackService extends Service implements AudioManager.OnAudioFocusChangeListener {
private static final String TAG = Log.buildTag(PlaybackService.class);
public static String stopButtonNotification = "";
public static final String ACTION_TOGGLE_PLAYBACK = "com.test.app.actions.TOGGLE_PLAYBACK";
public static final String ACTION_STOP_PLAYBACK = "com.test.app.actions.STOP_PLAYBACK";
public static final String ACTION_PAUSE_PLAYBACK = "com.test.app.actions.PAUSE_PLAYBACK";
public static final String ACTION_STOP = "com.test.app.actions.STOP";
public static String focusLoss = "";
public final int NOTIFICATION_ID = 1231231;
final Streamer streamer = Streamer.getInstance();
private final IBinder binder = new LocalBinder();
private PowerManager.WakeLock wakeLock;
private WifiManager.WifiLock wifiLock;
private RemoteControlClient remoteControlClient;
private ComponentName remoteControlReceiver;
public static MediaSession mediaSession;
public static Timer mTimerReconnect;
public static MyTimerReconnect myTimerReconnect;
@Override
public void onCreate() {
super.onCreate();
EventBus.getInstance().register(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mediaSession = new MediaSession(this, "com.test.app");
mediaSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
final Intent intent = new Intent(this, StationActivity.class);
mediaSession.setSessionActivity(PendingIntent.getActivity(this, 0, intent, 0));
} else {
remoteControlReceiver = new ComponentName(getPackageName(), PlaybackReceiver.class.getName());
final Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.setComponent(remoteControlReceiver);
final PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, 0);
remoteControlClient = new RemoteControlClient(mediaPendingIntent);
}
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getInstance().unregister(this);
Streamer.getInstance().destroy();
ensureUnlocked();
releaseAudioFocus();
//off
unregisterRemote();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mediaSession.release();
}
mTimerReconnect.cancel();
myTimerReconnect.cancel();
}
@Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
final String action = intent != null ? intent.getAction() : null;
if (ACTION_STOP.equals(action)) {
updateNotification();
streamer.stopped();
stopForeground(true);
}
if (ACTION_TOGGLE_PLAYBACK.equals(action)) {
togglePlayback();
} else if (ACTION_STOP_PLAYBACK.equals(action)) {
stopButtonNotification = "stop";
streamer.pause();
Streamer.getInstance().stopped();
Streamer.getInstance().isStoppedButton();
releaseAudioFocus();
} else if (ACTION_PAUSE_PLAYBACK.equals(action)) {
setPlaying(false);
} else {
return super.onStartCommand(intent, flags, startId);
}
return START_STICKY;
}
@Nullable
@Override
public IBinder onBind(final Intent intent) {
return binder;
}
private boolean requestAudioFocus() {
final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
final int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
private boolean releaseAudioFocus() {
final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
final int result = audioManager.abandonAudioFocus(this);
return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
private void ensureLocked() {
if (wakeLock == null) {
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "com.test.app");
wakeLock.acquire();
}
if (wifiLock == null) {
wifiLock = ((WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE)).createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "headspace");
wifiLock.acquire();
}
}
private void ensureUnlocked() {
if (wakeLock != null) {
wakeLock.release();
wakeLock = null;
}
if (wifiLock != null) {
wifiLock.release();
wifiLock = null;
}
}
public void buildNotification(final Bitmap bitmap) {
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
final Notification notification = PlaybackNotification.getInstance(this, bitmap, mediaSession);
nm.notify(NOTIFICATION_ID, notification);
startForeground(NOTIFICATION_ID, notification);
}
private void updateNotification() {
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
final Streamer streamer = Streamer.getInstance();
if (streamer.isStopped()) {
nm.cancel(NOTIFICATION_ID);
stopForeground(true);
} else {
Picasso.with(this).load(streamer.getStation().getIconUrl()).into(new Target() {
@Override
public void onBitmapLoaded(final Bitmap bitmap, final com.squareup.picasso.Picasso.LoadedFrom from) {
buildNotification(bitmap);
}
@Override
public void onBitmapFailed(final Drawable errorDrawable) {
buildNotification(null);
}
@Override
public void onPrepareLoad(final Drawable placeHolderDrawable) {
buildNotification(null);
}
});
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void startMediaSession() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
return;
mediaSession.setActive(true);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void stopMediaSession() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
return;
mediaSession.setActive(false);
}
// FIXME support new api
private void registerRemote() {
final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
if (remoteControlReceiver != null) {
am.registerMediaButtonEventReceiver(remoteControlReceiver);
}
if (remoteControlClient != null) {
am.registerRemoteControlClient(remoteControlClient);
}
}
private void unregisterRemote() {
final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
if (remoteControlReceiver != null) {
am.unregisterMediaButtonEventReceiver(remoteControlReceiver);
}
if (remoteControlClient != null) {
am.unregisterRemoteControlClient(remoteControlClient);
}
}
private void duck() {
Streamer.getInstance().setVolume(0.3f);
}
private void unduck() {
Streamer.getInstance().setVolume(1);
}
public void loadStation(final Station station) {
Streamer.getInstance().loadStation(station);
}
public void togglePlayback() {
final Streamer streamer = Streamer.getInstance();
setPlaying(!streamer.isPlaying());
}
public void setPlaying(final boolean state) {
final Streamer streamer = Streamer.getInstance();
if (!state) {
streamer.pause();
} else {
if (streamer.isStoppedButton())
streamer.loadStation(streamer.getStation());
streamer.start();
}
}
public void stopPlayback() {
}
@Override
public void onAudioFocusChange(final int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
unduck();
Log.i(TAG,"AUDIOFOCUS_GAIN");
break;
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
unduck();
Log.i(TAG,"AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE");
break;
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
unduck();
Log.i(TAG,"AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK");
break;
case AudioManager.AUDIOFOCUS_LOSS:
setPlaying(false);
Log.i(TAG,"AUDIOFOCUS_LOSS");
focusLoss = "loss";
//Streamer.getInstance().isStoppedButton();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
Streamer.getInstance().setVolume(0.1f);
setPlaying(false);
PlayerView.stopbutton.setVisibility(View.INVISIBLE);
PlayerView.playbutton.setVisibility(View.VISIBLE);
Log.i(TAG,"AUDIOFOCUS_LOSS_TRANSIENT");
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
duck();
Log.i(TAG,"AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK");
break;
default:
break;
}
}
@Subscribe
public void onMetadataUpdated(final StreamMetaDataUpdate update) {
updateNotification();
}
private static class MyTimerReconnect extends TimerTask {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Streamer streamer = Streamer.getInstance();
if (Streamer.getInstance().isBuffered()){
streamer.loadStation(streamer.getStation());
}
}
});
}
}
public static void onStreamerReconnect() {
if (myTimerReconnect != null) {
myTimerReconnect.cancel();
}
if(mTimerReconnect != null) {
mTimerReconnect.cancel();
}
mTimerReconnect = new Timer();
myTimerReconnect = new MyTimerReconnect();
mTimerReconnect.schedule(myTimerReconnect, 5000, 3000);
}
@Subscribe
public void onPlayerStateChanged(final PlayerStateChange update) {
try {
updateNotification();
}catch (Exception i){
i.printStackTrace();
Crashlytics.logException(i);
}
try {
if(Streamer.getInstance().isPlaying()){
switch (settingsMain.getString(RECONNECT_STATION, "")) {
case "1":
onStreamerReconnect();
break;
case "0":
//
break;
default:
onStreamerReconnect();
break;
}
}
} catch (Exception e){
e.printStackTrace();
Crashlytics.logException(e);
}
if (!Streamer.getInstance().isStopped()) {
ensureLocked();
requestAudioFocus();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
startMediaSession();
} else {
registerRemote();
}
} else {
ensureUnlocked();
releaseAudioFocus();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
stopMediaSession();
} else {
unregisterRemote();
}
}
}
@Subscribe
public void onError(final PlayerError error) {
updateNotification();
}
@Subscribe
public void onStationUpdate(final StationUpdate update) {
updateNotification();
}
public class LocalBinder extends Binder {
public PlaybackService getService() {
return PlaybackService.this;
}
}
}
Добавьте: [1]
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel nc = new NotificationChannel("Channel Player", "Player", NotificationManager.IMPORTANCE_HIGH);
nm.createNotificationChannel(nc);
}
Сюда:
public void buildNotification(final Bitmap bitmap) {
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
final Notification notification = PlaybackNotification.getInstance(this, bitmap, mediaSession);
// аля так
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel nc = new NotificationChannel("Channel Player", "Player", NotificationManager.IMPORTANCE_HIGH);
nm.createNotificationChannel(nc);
}
nm.notify(NOTIFICATION_ID, notification);
startForeground(NOTIFICATION_ID, notification);
}
А также необходимо добавить:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId("Channel Player");
}
Сюда:
final PlaybackState.Builder stateBuilder = new PlaybackState.Builder()
.setState(PlaybackState.STATE_PLAYING, 0, 1)
.setActions((stream.isPlaying() ? PlaybackState.ACTION_PAUSE : PlaybackState.ACTION_PLAY) | PlaybackState.ACTION_STOP);
builder.setAutoCancel(false);
builder.setOngoing(true);
builder.setSmallIcon(R.drawable.ic_action_ui_radio);
if (bitmap != null)
builder.setLargeIcon(bitmap);
builder.setContentTitle(station.getName()
.replace(" ᵗᵒᵖ 1. ","")
.replace(" ᵗᵒᵖ 2. ","")
.replace(" ᵗᵒᵖ 3. ","")
.replace(" ᵗᵒᵖ 4. ",""));
builder.setContentText(text);
//аля так
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId("Channel Player");
}
По поводу:
всегда будет поверх приложения появляться и со звуком уведомления? [3]
Необходимо изменить:
NotificationManager.IMPORTANCE_HIGH [2]
Под свои нужды:
IMPORTANCE_DEFAULT
По умолчанию значение уведомления: показывает
везде, шумит, но визуально не вмешиваться. IMPORTANCE_HIGH
Большее значение уведомления: показывает везде, делает шум и заглядывает.IMPORTANCE_LOW
Низкая важность уведомления: показывает везде, но не навязчивым. IMPORTANCE_MAX
Неиспользуемые. IMPORTANCE_MIN
Значение min уведомления: показывает только в занавеске. IMPORTANCE_NONE
Уведомление с не важно: не показывать в занавеске. IMPORTANCE_UNSPECIFIED
Значение, означающее, что пользователь не выразил важность. Источники: 1, 2, 3
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок