Zirak Mistry
Zirak Mistry

Reputation: 15

How to use notification channels in android O

I am a beginner in android and right now working on a music streaming app. I have taken a course on Udemy for beginners for that and the instructor goes line by line showing each step of creation,and i do exactly what he does. Now that we have reached the step of creating a notification for the app, he uses something called 'NotificationCompat.Builder(this)'. Now when I type the same exact code, I get an error saying that the NotificationCompat.Builder(context) has been deprecated now in android O. Due to this I am not getting the notifications on my phone when I run it. Also the music is not being streamed. Due to this I am not able to proceed with further lectures. I tried to ask the instructor on the forum for some help regarding this, but he does not seem to reply back. Also I tried to research about the notification channels in android O, but I am unable to understand the concepts due to the lack of knowledge on basic android. So it would be great if I could get some help regarding my problem. I am uploading my code along with this. The error is in PlayerService.java

(1). activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.music.zirakmistry.musicstreamingapp.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        app:srcCompat="@android:drawable/ic_media_play" />

</android.support.design.widget.CoordinatorLayout>

(2). MainActivity.java

public class MainActivity extends AppCompatActivity {

    static FloatingActionButton playPauseButton;
    PlayerService mBoundService;
    boolean mServiceBound=false;

    private ServiceConnection mServiceConnection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            PlayerService.MyBinder myBinder=(PlayerService.MyBinder)service;
            mBoundService=myBinder.getService();
            mServiceBound=true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name){
            mServiceBound=false;
        }
    };

    private BroadcastReceiver mMessageReceiver=new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            boolean isPlaying=intent.getBooleanExtra("isPlaying",false);
            flipPlayPauseButton(isPlaying);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        playPauseButton = (FloatingActionButton) findViewById(R.id.fab);
        playPauseButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view){
                if(mServiceBound)
                    mBoundService.togglePlayer();
            }
        });
        startStreamingService("https://www.mymusicstreamingapp.com/music_app/cute.mp3");
    }

    private void startStreamingService(String url)
    {
        Intent i=new Intent(this,PlayerService.class);
        i.putExtra("url",url);
        i.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
        startService(i);
        bindService(i,mServiceConnection,Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        if(mServiceBound){
            unbindService(mServiceConnection);
            mServiceBound=false;
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,new IntentFilter("changePlayButton"));
    }

    @Override
    protected void onPause() {
        super.onPause();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
    }

    public static void flipPlayPauseButton(boolean isPlaying){
        if(isPlaying){
            playPauseButton.setImageResource(android.R.drawable.ic_media_pause);
        }
        else{
            playPauseButton.setImageResource(android.R.drawable.ic_media_play);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

(3). PlayerService.java

public class PlayerService extends Service {

    MediaPlayer mediaPlayer=new MediaPlayer();
    private final IBinder mBinder=new MyBinder();

    public class MyBinder extends Binder
    {
        PlayerService getService()
        {
            return PlayerService.this;
        }
    }

    public PlayerService()
    {

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        if(intent.getStringArrayExtra("url")!=null)
            playStream(intent.getStringExtra("url"));

        if(intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION))
        {
            Log.i("info","Start foregroung service");
            showNotification();
        }
        else if(intent.getAction().equals(Constants.ACTION.PREV_ACTION))
        {
            Log.i("info","Prev pressed");
        }
        else if(intent.getAction().equals(Constants.ACTION.PLAY_ACTION))
        {
            Log.i("info","Play pressed");
        }
        else if(intent.getAction().equals(Constants.ACTION.NEXT_ACTION))
        {
            Log.i("info","Next pressed");
        }
        else if(intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION))
        {
            Log.i("info","Stop foreground received");
            stopForeground(true);
            stopSelf();
        }

        return START_REDELIVER_INTENT;
    }

    private void showNotification()
    {
        Intent notificationIntent=new Intent(this,MainActivity.class);
        notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);
        notificationIntent.setFlags((Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));
        PendingIntent pendingIntent=PendingIntent.getActivity(this,0,notificationIntent,0);

        Intent previousIntent=new Intent(this,MainActivity.class);
        previousIntent.setAction(Constants.ACTION.PREV_ACTION);
        PendingIntent ppreviousIntent=PendingIntent.getActivity(this,0,previousIntent,0);

        Intent playIntent=new Intent(this,MainActivity.class);
        playIntent.setAction(Constants.ACTION.PLAY_ACTION);
        PendingIntent pplayIntent=PendingIntent.getActivity(this,0,playIntent,0);

        Intent nextIntent=new Intent(this,MainActivity.class);
        nextIntent.setAction(Constants.ACTION.NEXT_ACTION);
        PendingIntent pnextIntent=PendingIntent.getActivity(this,0,nextIntent,0);

        Bitmap icon= BitmapFactory.decodeResource(getResources(),R.drawable.logo);

        Notification notification=new NotificationCompat.Builder(this)
                .setContentTitle("Music Player")
                .setTicker("Playing music")
                .setContentText("My Song")
                .setSmallIcon(R.drawable.logo)
                .setLargeIcon(Bitmap.createScaledBitmap(icon,128,128,false))
                .setContentIntent(pendingIntent)
                .setOngoing(true)
                .addAction(android.R.drawable.ic_media_previous,"Previous",ppreviousIntent)
                .addAction(android.R.drawable.ic_media_play,"Play",pplayIntent)
                .addAction(android.R.drawable.ic_media_next,"Next",pnextIntent)
                .build();
        startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE,notification);
    }

    @Override
    public IBinder onBind(Intent intent)
    {
        return mBinder;
    }

    public void playStream(String url)
    {
        if(mediaPlayer!=null)
        {
            try
            {
                mediaPlayer.stop();
            }
            catch(Exception e)
            {
            }
            mediaPlayer=null;
        }

        mediaPlayer=new MediaPlayer();
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        try
        {
            mediaPlayer.setDataSource(url);
            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener()
            {
                @Override
                public void onPrepared(MediaPlayer mp)
                {
                    playPlayer();
                }
            });
            mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
            {
                @Override
                public void onCompletion(MediaPlayer mp)
                {
                    flipPlayPauseButton(false);
                }
            });
            mediaPlayer.prepareAsync();
        }
        catch(IOException e)
        {
            e.printStackTrace();
        }
    }

    public void pausePlayer()
    {
        try
        {
            mediaPlayer.pause();
            flipPlayPauseButton(false);
        }
        catch(Exception e)
        {
            Log.d("EXCEPTION","failed to pause media player");
        }
    }

    public void playPlayer()
    {
        try
        {
            mediaPlayer.start();
            flipPlayPauseButton(true);
        }
        catch(Exception e)
        {
            Log.d("EXCEPTION","failed to pause media player");
        }
    }

    public void flipPlayPauseButton(boolean isPlaying)
    {
        // code to communicate with main thread
        Intent intent=new Intent("changePlayButton");
        //add data
        intent.putExtra("isPlaying",isPlaying);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    public void togglePlayer()
    {
        try
        {
            if(mediaPlayer.isPlaying())
                pausePlayer();
            else
                playPlayer();
        }
        catch(Exception e)
        {
            Log.d("Exception","failed to toggle media player");
        }
    }
}

(4). Player.java

public class Player {
    MediaPlayer mediaPlayer=new MediaPlayer();
    public static Player player;
    String url="";

    public Player()
    {
        this.player = this;
    }

    public void playStream(String url)
    {
        if(mediaPlayer!=null)
        {
            try
            {
                mediaPlayer.stop();
            }
            catch(Exception e)
            {
            }
            mediaPlayer=null;
        }

        mediaPlayer=new MediaPlayer();
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        try
        {
            mediaPlayer.setDataSource(url);
            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener()
            {
                @Override
                public void onPrepared(MediaPlayer mp)
                {
                    playPlayer();
                }
            });
            mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
            {
                @Override
                public void onCompletion(MediaPlayer mp)
                {
                    MainActivity.flipPlayPauseButton(false);
                }
            });
            mediaPlayer.prepareAsync();
        }
        catch(IOException e)
        {
            e.printStackTrace();
        }
    }

    public void pausePlayer()
    {
        try
        {
            mediaPlayer.pause();
            MainActivity.flipPlayPauseButton(false);
        }
        catch(Exception e)
        {
            Log.d("EXCEPTION","failed to pause media player");
        }
    }

    public void playPlayer()
    {
        try
        {
            mediaPlayer.start();
            MainActivity.flipPlayPauseButton(true);
        }
        catch(Exception e)
        {
            Log.d("EXCEPTION","failed to pause media player");
        }
    }

    public void togglePlayer()
    {
        try
        {
            if(mediaPlayer.isPlaying())
                pausePlayer();
            else
                playPlayer();
        }
        catch(Exception e)
        {
            Log.d("Exception","failed to toggle media player");
        }
    }
}

(5). Constants.java

public class Constants {
    public interface ACTION {
        public static String MAIN_ACTION="com.music.zirakmistry.musicstreamingapp.action.main";
        public static String PREV_ACTION="com.music.zirakmistry.musicstreamingapp.action.prev";
        public static String PLAY_ACTION="com.music.zirakmistry.musicstreamingapp.action.play";
        public static String NEXT_ACTION="com.music.zirakmistry.musicstreamingapp.action.next";
        public static String STARTFOREGROUND_ACTION="com.music.zirakmistry.musicstreamingapp.action.startforeground";
        public static String STOPFOREGROUND_ACTION="com.music.zirakmistry.musicstreamingapp.action.stopforeground";
    }

    public interface NOTIFICATION_ID
    {
        public static int FOREGROUND_SERVICE=101;
    }
}

(6). AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.music.zirakmistry.musicstreamingapp">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar"
            android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".PlayerService"
            android:enabled="true"
            android:exported="true" />
    </application>

</manifest>

Upvotes: 0

Views: 3236

Answers (1)

Srijith
Srijith

Reputation: 1715

In order to facilitate the new feature called Notification Channels in Android Oreo the previous method was deprecated.

Notification Channels allow us to group notifications based on their intended behavior. So whenever a user don't need to see a specific type of notification they can disable the corresponding channel.

So for example consider an e-commerce app. It shows notifications for promotions/offers, order status, etc. Promotion and offer notifications are grouped into a channel named "promotion". So if the user don't want to see only these notifications they can disable the "promotion" channel from the app settings.

If you use the deprecated method, the notification will fail silently in Oreo. To make it work, use the new Builder constructor. Change your code as below:

Notification notification=new NotificationCompat.Builder(this, CHANNEL_ID)
    // set title, message, etc.
    .build();

And create a notification channel like this for Oreo:

NotificationManager manager =
    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    // Support for Android Oreo: Notification Channels
    NotificationChannel channel = new NotificationChannel(
                CHANNEL_ID,
                "Channel_name_to_be_displayed_in_Settings",
                NotificationManager.IMPORTANCE_DEFAULT);
    manager.createNotificationChannel(channel);
}

Upvotes: 4

Related Questions