Привет, ребята, я создаю приложение для потокового радио , я застрял в проблеме. Когда я нажимаю кнопку «Назад» на главном экране go телефона, он прекращает воспроизведение и пропадает уведомление, но когда я играю и go возвращаюсь на главный экран нажатием кнопки «Домой», он работает хорошо и продолжает показывать уведомление. Я хочу чтобы показать управление уведомлением и продолжить воспроизведение даже go назад или уничтожить приложение до тех пор, пока не будет нажата кнопка остановки уведомления ... в уведомлении есть 2 кнопки (воспроизведение / остановка). пожалуйста, помогите мне достичь этого ... спасибо
Это мое приложение в магазине Play ..
Это мой сервис Класс
public class MyService extends Service implements Player.EventListener, AudioManager.OnAudioFocusChangeListener {
public static final String ACTION_PLAY = "action_play";
public static final String ACTION_PAUSE = "action_pause";
public static final String ACTION_STOP = "action_stop";
private final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();
private MediaControllerCompat.TransportControls transportControls;
private final IBinder iBinder = new LocalBinder();
private NotifyClass notifyClass;
private TelephonyManager telephonyManager;
private MediaSessionCompat mediaSession;
private boolean isOnGoingCall = false;
private WifiManager.WifiLock wifiLock;
public static SimpleExoPlayer exoPlayer;
private AudioManager audioManager;
private String strLiveBroadcast;
private String myAppName;
private Handler mHandler;
private String streamUrl;
private String status;
private boolean isExoNull;
public class LocalBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
private BroadcastReceiver becomingNoisyReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
pause();
}
};
private PhoneStateListener phoneStateListener = new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
if(state == TelephonyManager.CALL_STATE_OFFHOOK
|| state == TelephonyManager.CALL_STATE_RINGING){
if(!isPlaying()) return;
isOnGoingCall = true;
stop();
} else if (state == TelephonyManager.CALL_STATE_IDLE){
if(!isOnGoingCall) return;
isOnGoingCall = false;
resume();
}
}
};
private MediaSessionCompat.Callback mediasSessionCallback = new MediaSessionCompat.Callback() {
@Override
public void onPause() {
super.onPause();
pause();
}
@Override
public void onStop() {
super.onStop();
stop();
notifyClass.cancelNotify();
}
@Override
public void onPlay() {
super.onPlay();
resume();
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
@Override
public void onCreate() {
super.onCreate();
myAppName = getResources().getString(R.string.app_name);
strLiveBroadcast = getResources().getString(R.string.notify_h1);
isOnGoingCall = false;
isExoNull = true;
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
notifyClass = new NotifyClass(this);
wifiLock = ((WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE))
.createWifiLock(WifiManager.WIFI_MODE_FULL, "mcScPAmpLock");
mediaSession = new MediaSessionCompat(this, getClass().getSimpleName());
transportControls = mediaSession.getController().getTransportControls();
mediaSession.setActive(true);
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mediaSession.setMetadata(new MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, "...")
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, myAppName)
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, strLiveBroadcast)
.build());
mediaSession.setCallback(mediasSessionCallback);
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
mHandler = new Handler();
exoPlayer = ExoPlayerFactory.newSimpleInstance(getApplicationContext(), new DefaultTrackSelector());
exoPlayer.addListener(this);
registerReceiver(becomingNoisyReceiver, new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
status = HandlerPlay.IDLE;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
MediaButtonReceiver.handleIntent(mediaSession, intent);
String action = intent.getAction();
if(TextUtils.isEmpty(action))
return START_NOT_STICKY;
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if(result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED){
stop();
return START_NOT_STICKY;
}
if(action.equalsIgnoreCase(ACTION_PLAY)){
transportControls.play();
} else if(action.equalsIgnoreCase(ACTION_PAUSE)) {
transportControls.pause();
} else if(action.equalsIgnoreCase(ACTION_STOP)){
transportControls.stop();
}
return START_NOT_STICKY;
}
@Override
public boolean onUnbind(Intent intent) {
if(status.equals(HandlerPlay.IDLE))
stopSelf();
return super.onUnbind(intent);
}
@Override
public void onRebind(final Intent intent) {
}
@Override
public void onDestroy() {
pause();
if (!isExoNull) {
if (exoPlayer != null) {
exoPlayer.release();
exoPlayer.removeListener(this);
exoPlayer = null;
}
isExoNull = true;
}
if(telephonyManager != null)
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
notifyClass.cancelNotify();
mediaSession.release();
unregisterReceiver(becomingNoisyReceiver);
super.onDestroy();
}
@Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
exoPlayer.setVolume(0.8f);
resume();
break;
case AudioManager.AUDIOFOCUS_LOSS:
stop();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
if (isPlaying()) pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
if (isPlaying())
exoPlayer.setVolume(0.1f);
break;
}
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
switch (playbackState) {
case Player.STATE_BUFFERING:
status = HandlerPlay.LOADING;
break;
case Player.STATE_ENDED:
status = HandlerPlay.STOPPED;
break;
case Player.STATE_IDLE:
status = HandlerPlay.IDLE;
break;
case Player.STATE_READY:
status = playWhenReady ? HandlerPlay.PLAYING : HandlerPlay.PAUSED;
break;
default:
status = HandlerPlay.IDLE;
break;
}
if(!status.equals(HandlerPlay.IDLE))
notifyClass.startNotify(status);
EventBus.getDefault().post(status);
}
@Override
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
}
@Override
public void onLoadingChanged(boolean isLoading) {
}
@Override
public void onPlayerError(ExoPlaybackException error) {
EventBus.getDefault().post(HandlerPlay.ERROR);
}
@Override
public void onRepeatModeChanged(int repeatMode) {
}
@Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
}
@Override
public void onPositionDiscontinuity(int reason) {
}
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
}
@Override
public void onSeekProcessed() {
}
public void play(String streamUrl) {
this.streamUrl = streamUrl;
if (wifiLock != null && !wifiLock.isHeld()) {
wifiLock.acquire();
}
// DefaultHttpDataSourceFactory dataSourceFactory = new DefaultHttpDataSourceFactory(getUserAgent());
DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(this, getUserAgent(), BANDWIDTH_METER);
ExtractorMediaSource mediaSource = new ExtractorMediaSource.Factory(dataSourceFactory)
.setExtractorsFactory(new DefaultExtractorsFactory())
.createMediaSource(Uri.parse(streamUrl));
exoPlayer.prepare(mediaSource);
exoPlayer.setPlayWhenReady(true);
}
public void resume() {
if(streamUrl != null)
play(streamUrl);
}
public void pause() {
exoPlayer.setPlayWhenReady(false);
audioManager.abandonAudioFocus(this);
wifiLockRelease();
}
public void stop() {
exoPlayer.stop();
audioManager.abandonAudioFocus(this);
wifiLockRelease();
}
public void playOrPause(String url){
if(streamUrl != null && streamUrl.equals(url)){
if(!isPlaying()){
play(streamUrl);
} else {
pause();
}
} else {
if(isPlaying()){
pause();
}
play(url);
}
}
public String getStatus(){
return status;
}
public MediaSessionCompat getMediaSession(){
return mediaSession;
}
public boolean isPlaying(){
return this.status.equals(HandlerPlay.PLAYING);
}
private void wifiLockRelease(){
if (wifiLock != null && wifiLock.isHeld()) {
wifiLock.release();
}
}
private String getUserAgent(){
return Util.getUserAgent(this, getClass().getSimpleName());
}
}
Ниже приведен класс уведомлений
public class NotifyClass {
public static final String PRIMARY_CHANNEL = "PRIMARY_CHANNEL_ID";
public final String PRIMARY_CHANNEL_NAME = "PRIMARY";
private NotificationManagerCompat notificationManager;
public static final int NOTIFICATION_ID = 555;
private Resources resources;
private MyService service;
public NotifyClass(MyService service) {
this.service = service;
this.resources = service.getResources();
notificationManager = NotificationManagerCompat.from(service);
}
public void startNotify(String playbackStatus) {
Bitmap largeIcon = BitmapFactory.decodeResource(resources, R.drawable.radio_icon_light);
int icon = R.drawable.ic_pause_white;
Intent playbackAction = new Intent(service, MyService.class);
playbackAction.setAction(MyService.ACTION_PAUSE);
PendingIntent action = PendingIntent.getService(service, 1, playbackAction, 0);
if(playbackStatus.equals(HandlerPlay.PAUSED)){
icon = R.drawable.exo_notification_play;
playbackAction.setAction(MyService.ACTION_PLAY);
action = PendingIntent.getService(service, 2, playbackAction, 0);
}
Intent stopIntent = new Intent(service, MyService.class);
stopIntent.setAction(MyService.ACTION_STOP);
PendingIntent stopAction = PendingIntent.getService(service, 3, stopIntent, 0);
Intent intent = new Intent(service, MainActivity.class);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
PendingIntent pendingIntent = PendingIntent.getActivity(service, 0, intent, 0);
notificationManager.cancel(NOTIFICATION_ID);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(PRIMARY_CHANNEL, PRIMARY_CHANNEL_NAME,
NotificationManager.IMPORTANCE_LOW);
channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
NotificationManager manager = (NotificationManager) service.getSystemService(Context.NOTIFICATION_SERVICE);
if (manager != null) {
manager.createNotificationChannel(channel);
}
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(service, PRIMARY_CHANNEL)
.setOngoing(true)
.setAutoCancel(false)
.setContentTitle(PLAY_NAME)
.setContentText(PLAY_FRQ)
.setLargeIcon(largeIcon)
.setContentIntent(pendingIntent)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setSmallIcon(R.drawable.radio_small)
.addAction(icon, "pause", action)
.addAction(R.drawable.exo_notification_stop, "stop", stopAction)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setWhen(System.currentTimeMillis())
.setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
.setMediaSession(service.getMediaSession().getSessionToken())
.setShowActionsInCompactView(0, 1)
.setShowCancelButton(true)
.setCancelButtonIntent(stopAction));
service.startForeground(NOTIFICATION_ID, builder.build());
}
public void cancelNotify() {
service.stopForeground(true);
}
}
Ниже указан класс обработчика
public class HandlerPlay {
public static final String IDLE = "Radio_IDLE";
public static final String LOADING = "Radio_LOADING";
public static final String PLAYING = "Radio_PLAYING";
public static final String PAUSED = "Radio_PAUSED";
public static final String STOPPED = "Radio_STOPPED";
public static final String ERROR = "Radio_ERROR";
}
Ниже указан манифест
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="xxx.xxx.xxx">
<permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name=".util.AppController"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
<activity android:name=".ChatActivity"
android:label="Live Chat"
android:theme="@style/ChatBackground"
android:screenOrientation="portrait"/>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:configChanges="orientation|screenSize"
android:theme="@style/AppTheme.NoActionBar" />
<activity android:name=".PrivacyPolicy" />
<activity
android:name=".SplashActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.SplashScreen">
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchconfig" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="androidx.media.session.MediaButtonReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
<service android:name=".services.MyService">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</service>
<meta-data
android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" />
</application>
</manifest>