Deimantas Brandišauskas
Deimantas Brandišauskas

Reputation: 1772

Extending my Android Radio Application

Recently, I uploaded simple Radio Application to the Google Play Store. And it has kinda a lot of downloaders. But it was really simple and I want to extend that Radio App to the next level. What it has for now is only ONE radio station to choose. No next, no previous buttons to choose from more Radio Stations. What I really want to do is to extend it so the user can listen for more Radio Stations(not one, but about 6 more or so). So maybe I need to add Previous and Next buttons to the app so the user can actually do that. But there is a problem - I don't know how to do this.

This is MainActivity.java class :

public class MainActivity extends Activity {

    static String radioTitle = "RadioLink1";
    static String radioStreamURL = "http://108.61.73.117:8124";

    Button playButton;
    Button pauseButton;
    Button stopButton;
    TextView statusTextView, bufferValueTextView;
    NotificationCompat.Builder notifyBuilder;

    private SeekBar volumeSeekbar;
    private AudioManager audioManager = null;

    private RadioUpdateReceiver radioUpdateReceiver;
    private RadioService radioServiceBinder;

    // Notification
    private static final int NOTIFY_ME_ID = 12345;
    private NotificationManager notifyMgr = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView titleTextView = (TextView) this
                .findViewById(R.id.titleTextView);
        titleTextView.setText(radioTitle);

        playButton = (Button) this.findViewById(R.id.PlayButton);
        pauseButton = (Button) this.findViewById(R.id.PauseButton);
        stopButton = (Button) this.findViewById(R.id.StopButton);
        playButton.setEnabled(true);
        pauseButton.setEnabled(false);
        stopButton.setEnabled(false);
        pauseButton.setVisibility(View.INVISIBLE);

        initControls();

        statusTextView = (TextView) this
                .findViewById(R.id.StatusDisplayTextView);

        notifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        showNotification();

        setFont();

        // Bind to the service
        Intent bindIntent = new Intent(this, RadioService.class);
        bindService(bindIntent, radioConnection, Context.BIND_AUTO_CREATE);
        startService(new Intent(this, RadioService.class));
    }

    private void initControls() {
        try {

            audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
            volumeSeekbar.setMax(audioManager
                    .getStreamMaxVolume(AudioManager.STREAM_MUSIC));
            volumeSeekbar.setProgress(audioManager
                    .getStreamVolume(AudioManager.STREAM_MUSIC));

            volumeSeekbar
                    .setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
                        @Override
                        public void onStopTrackingTouch(SeekBar arg0) {
                        }

                        @Override
                        public void onStartTrackingTouch(SeekBar arg0) {
                        }

                        @Override
                        public void onProgressChanged(SeekBar arg0,
                                int progress, boolean arg2) {
                            audioManager.setStreamVolume(
                                    AudioManager.STREAM_MUSIC, progress, 0);
                        }
                    });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setFont() {
        // Font path
        String fontPath = "fonts/Christmas Card.ttf";

        // text view label
        TextView txtGhost = (TextView) findViewById(R.id.titleTextView);

        // Loading Font Face
        Typeface tf = Typeface.createFromAsset(getAssets(), fontPath);

        // Applying font
        txtGhost.setTypeface(tf);
    }

    public void onClickPlayButton(View view) {
        radioServiceBinder.play();
    }

    public void onClickPauseButton(View view) {
        radioServiceBinder.pause();
    }

    public void onClickStopButton(View view) {
        radioServiceBinder.stop();
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (radioUpdateReceiver != null)
            unregisterReceiver(radioUpdateReceiver);
    }

    @Override
    protected void onResume() {
        super.onResume();

        /* Register for receiving broadcast messages */
        if (radioUpdateReceiver == null)
            radioUpdateReceiver = new RadioUpdateReceiver();
        registerReceiver(radioUpdateReceiver, new IntentFilter(
                RadioService.MODE_CREATED));
        registerReceiver(radioUpdateReceiver, new IntentFilter(
                RadioService.MODE_DESTROYED));
        registerReceiver(radioUpdateReceiver, new IntentFilter(
                RadioService.MODE_STARTED));
        registerReceiver(radioUpdateReceiver, new IntentFilter(
                RadioService.MODE_PREPARED));
        registerReceiver(radioUpdateReceiver, new IntentFilter(
                RadioService.MODE_PLAYING));
        registerReceiver(radioUpdateReceiver, new IntentFilter(
                RadioService.MODE_PAUSED));
        registerReceiver(radioUpdateReceiver, new IntentFilter(
                RadioService.MODE_STOPPED));
        registerReceiver(radioUpdateReceiver, new IntentFilter(
                RadioService.MODE_COMPLETED));
        registerReceiver(radioUpdateReceiver, new IntentFilter(
                RadioService.MODE_ERROR));
        registerReceiver(radioUpdateReceiver, new IntentFilter(
                RadioService.MODE_BUFFERING_START));
        registerReceiver(radioUpdateReceiver, new IntentFilter(
                RadioService.MODE_BUFFERING_END));
    }

    /* Receive Broadcast Messages from RadioService */
    private class RadioUpdateReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {

            if (intent.getAction().equals(RadioService.MODE_CREATED)) {
                showNotification();
            } else if (intent.getAction().equals(RadioService.MODE_DESTROYED)) {
                clearNotification();
            } else if (intent.getAction().equals(RadioService.MODE_STARTED)) {
                playButton.setEnabled(false);
                pauseButton.setEnabled(false);
                stopButton.setEnabled(true);
                playButton.setVisibility(View.VISIBLE);
                pauseButton.setVisibility(View.INVISIBLE);
                updateStatus("Buffering...");
            } else if (intent.getAction().equals(RadioService.MODE_PREPARED)) {
                playButton.setEnabled(true);
                pauseButton.setEnabled(false);
                stopButton.setEnabled(false);
                playButton.setVisibility(View.VISIBLE);
                pauseButton.setVisibility(View.INVISIBLE);
                updateStatus("Rady");
            } else if (intent.getAction().equals(
                    RadioService.MODE_BUFFERING_START)) {
                updateStatus("Buffering...");
            } else if (intent.getAction().equals(
                    RadioService.MODE_BUFFERING_END)) {
                updateStatus("Playing");
            } else if (intent.getAction().equals(RadioService.MODE_PLAYING)) {
                playButton.setEnabled(false);
                pauseButton.setEnabled(true);
                stopButton.setEnabled(true);
                playButton.setVisibility(View.INVISIBLE);
                pauseButton.setVisibility(View.VISIBLE);
                showNotification();
                updateStatus("Playing");
            } else if (intent.getAction().equals(RadioService.MODE_PAUSED)) {
                playButton.setEnabled(true);
                pauseButton.setEnabled(false);
                stopButton.setEnabled(true);
                playButton.setVisibility(View.VISIBLE);
                pauseButton.setVisibility(View.INVISIBLE);
                updateStatus("Paused");
            } else if (intent.getAction().equals(RadioService.MODE_STOPPED)) {
                playButton.setEnabled(true);
                pauseButton.setEnabled(false);
                stopButton.setEnabled(false);
                playButton.setVisibility(View.VISIBLE);
                pauseButton.setVisibility(View.INVISIBLE);
                updateStatus("Stopped");
                clearNotification();
            } else if (intent.getAction().equals(RadioService.MODE_COMPLETED)) {
                playButton.setEnabled(true);
                pauseButton.setEnabled(false);
                stopButton.setEnabled(false);
                playButton.setVisibility(View.VISIBLE);
                pauseButton.setVisibility(View.INVISIBLE);
                updateStatus("Stopped");
            } else if (intent.getAction().equals(RadioService.MODE_ERROR)) {
                playButton.setEnabled(true);
                pauseButton.setEnabled(false);
                stopButton.setEnabled(false);
                playButton.setVisibility(View.VISIBLE);
                pauseButton.setVisibility(View.INVISIBLE);
                updateStatus("Error");
            }
        }
    }

    public void updateStatus(String status) {
        try {
            if (notifyBuilder != null && notifyMgr != null) {
                notifyBuilder.setContentText(status).setWhen(0);
                notifyMgr.notify(NOTIFY_ME_ID, notifyBuilder.build());
            }
            statusTextView.setText(status);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void showNotification() {
        notifyBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_launcher)
                .setContentTitle(radioTitle).setContentText("");
        Intent resultIntent = new Intent(this, MainActivity.class);
        resultIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addParentStack(MainActivity.class);
        stackBuilder.addNextIntent(resultIntent);

        PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
                PendingIntent.FLAG_UPDATE_CURRENT);

        notifyBuilder.setContentIntent(resultPendingIntent);
        notifyMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notifyMgr.notify(NOTIFY_ME_ID, notifyBuilder.build());
    }

    public void clearNotification() {
        notifyMgr.cancel(NOTIFY_ME_ID);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.about:
            Intent i = new Intent(this, AboutActivity.class);
            startActivity(i);
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    // Handles the connection between the service and activity
    private ServiceConnection radioConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            radioServiceBinder = ((RadioService.RadioBinder) service)
                    .getService();
        }

        public void onServiceDisconnected(ComponentName className) {
            radioServiceBinder = null;
        }
    };
}

and RadioService.java class:

public class RadioService extends Service implements OnErrorListener, OnCompletionListener, OnPreparedListener, OnInfoListener {

    private MediaPlayer mediaPlayer;
    private String radioStreamURL = MainActivity.radioStreamURL;

    public static final String MODE_CREATED = "CREATED";
    public static final String MODE_DESTROYED = "DESTROYED";
    public static final String MODE_PREPARED = "PREPARED";
    public static final String MODE_STARTED = "STARTED";
    public static final String MODE_PLAYING = "PLAYING";
    public static final String MODE_PAUSED = "PAUSED";
    public static final String MODE_STOPPED = "STOPPED";
    public static final String MODE_COMPLETED = "COMPLETED";
    public static final String MODE_ERROR = "ERROR";
    public static final String MODE_BUFFERING_START = "BUFFERING_START";
    public static final String MODE_BUFFERING_END = "BUFFERING_END";

    private boolean isPrepared = false;

    private final IBinder binder = new RadioBinder();

    @Override
    public void onCreate() {
        /* Create MediaPlayer when it starts for first time */
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setOnCompletionListener(this);
        mediaPlayer.setOnErrorListener(this);
        mediaPlayer.setOnPreparedListener(this);
        mediaPlayer.setOnInfoListener(this);

        sendBroadcast(new Intent(MODE_CREATED));
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mediaPlayer.stop();
        mediaPlayer.reset();
        isPrepared = false;
        sendBroadcast(new Intent(MODE_DESTROYED));
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {  
        sendBroadcast(new Intent(MODE_STARTED));

        /* Starts playback at first time or resumes if it is restarted */
        if(mediaPlayer.isPlaying())
            sendBroadcast(new Intent(MODE_PLAYING));
        else if(isPrepared) {
            sendBroadcast(new Intent(MODE_PAUSED));
        }
        else
            prepare();

        return Service.START_STICKY;
    }


    @Override
    public void onPrepared(MediaPlayer _mediaPlayer) {
        /* If radio is prepared then start playback */
        sendBroadcast(new Intent(MODE_PREPARED));
        isPrepared = true;
        play();
    }

    @Override
    public void onCompletion(MediaPlayer mediaPlayer) { 
        /* When no stream found then complete the playback */
        mediaPlayer.stop();
        mediaPlayer.reset();
        isPrepared = false;
        sendBroadcast(new Intent(MODE_COMPLETED));
    }

    public void prepare() {     
        /* Prepare Async Task - starts buffering */
        try {           
            mediaPlayer.setDataSource(radioStreamURL);
            mediaPlayer.prepareAsync();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void play() {
        if(isPrepared) {
            mediaPlayer.start();
            System.out.println("RadioService: play");
            sendBroadcast(new Intent(MODE_PLAYING));
        }
        else
        {
            sendBroadcast(new Intent(MODE_STARTED));
            prepare();
        }
    }

    public void pause() {
        mediaPlayer.pause();
        System.out.println("RadioService: pause");
        sendBroadcast(new Intent(MODE_PAUSED));
    }

    public void stop() {
        mediaPlayer.stop();
        mediaPlayer.reset();
        isPrepared = false;
        System.out.println("RadioService: stop");
        sendBroadcast(new Intent(MODE_STOPPED));
    }

    @Override
    public boolean onInfo(MediaPlayer mp, int what, int extra) {
        /* Check when buffering is started or ended */
        if(what == MediaPlayer.MEDIA_INFO_BUFFERING_START) {
            sendBroadcast(new Intent(MODE_BUFFERING_START));
        }
        else if(what == MediaPlayer.MEDIA_INFO_BUFFERING_END) {
            sendBroadcast(new Intent(MODE_BUFFERING_END));
        }

        return false;
    }


    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        sendBroadcast(new Intent(MODE_ERROR));
        switch (what) {
            case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
                Log.v("ERROR","MEDIA ERROR NOT VALID FOR PROGRESSIVE PLAYBACK " + extra);
                break;
            case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
                Log.v("ERROR","MEDIA ERROR SERVER DIED " + extra);
                break;
            case MediaPlayer.MEDIA_ERROR_UNKNOWN:
                Log.v("ERROR","MEDIA ERROR UNKNOWN " + extra);
                break;
        }
        return false;
    }


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

    /* Allowing activity to access all methods of RadioService */
    public class RadioBinder extends Binder {
        RadioService getService() {
            return RadioService.this;
        }
    }

}

And this layout:

  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#4a4a4a"
    tools:context=".MainActivity" >

    <LinearLayout
        android:id="@+id/player_header_bg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true" >

        <TextView
            android:id="@+id/titleTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="48dp"
            android:background="@color/bgcolor"
            android:gravity="center"
            android:text="Classic Christmas Radio"
            android:textAlignment="center"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textColor="#c0413b"
            android:textSize="40sp" />
    </LinearLayout>

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:layout_marginBottom="120dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="110dp"
        android:src="@drawable/cover" />

    <TextView
        android:id="@+id/StatusDisplayTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/PauseButton"
        android:layout_alignLeft="@+id/imageView1"
        android:layout_alignRight="@+id/imageView1"
        android:gravity="center"
        android:text="Unknown" />

    <Button
        android:id="@+id/PauseButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@id/StatusDisplayTextView"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="0.0dip"
        android:background="@drawable/btn_pause"
        android:onClick="onClickPauseButton" />

    <Button
        android:id="@+id/PlayButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@id/StatusDisplayTextView"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="0.0dip"
        android:background="@drawable/btn_play"
        android:onClick="onClickPlayButton" />

    <Button
        android:id="@+id/StopButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignRight="@id/StatusDisplayTextView"
        android:layout_marginBottom="0.0dip"
        android:background="@drawable/btn_stop"
        android:onClick="onClickStopButton" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_toRightOf="@+id/PauseButton"
        android:background="@drawable/btn_previous" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_toRightOf="@+id/button1"
        android:background="@drawable/btn_next" />

</RelativeLayout>

I actually didn't write all the code and that's why I can't get my head straight to the problem solution. I just extended given code for my needs but now I don't really now how to implement Previous and Next buttons to navigate through different Radio Stations. What I want from you guys is to maybe give me some ideas or just set me on the road how can I add this functionality to this app. How can I get more than one stream (in this case from SHOUTcast) and add this navigation through them. I hope I didn't breaking the StackOverflow rules of asking this kind of question. Thank you and appreciate any help.

UPDATE:

In the MainActivity:

static String radioTitle = "RadioStation1";
    static String radioStreamURL = "http://108.61.73.117:8124";

    static String radioTitle2 = "RadioStation2";
    static String radioStreamURL2 = "http://108.61.73.117:8124";

    static String radioTitle3 = "RadioStation3";
    static String radioStreamURL3 = "http://108.61.73.117:8124";

...........

nextButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

            }
        });

        prevButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

            }
        });

And the RadioService class:

private String radioStreamURL = MainActivity.radioStreamURL;
    private String radioStreamURL2 = MainActivity.radioStreamURL2;
    private String radioStreamURL3 = MainActivity.radioStreamURL3;

...............

public void prepare() {     
        /* Prepare Async Task - starts buffering */
        try {           
            mediaPlayer.setDataSource(radioStreamURL);
            mediaPlayer.setDataSource(radioStreamURL2);
            mediaPlayer.setDataSource(radioStreamURL3);
            mediaPlayer.prepareAsync();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Upvotes: 0

Views: 434

Answers (2)

user3255328
user3255328

Reputation:

I am not too experience in Android development, but you may need a complex algorithm developed if you would like to follow Spotify and Pandora's steps in the sense that the radio stations are created in relation to the listener's genre, etc.

Upvotes: 0

GhostDerfel
GhostDerfel

Reputation: 1551

Look at your method at RadioService.java

public void prepare() {     
        /* Prepare Async Task - starts buffering */
        try {           
            mediaPlayer.setDataSource(radioStreamURL);
            mediaPlayer.prepareAsync();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Here you set the URL to your radio stream, the fast way to change your code without knowing all your code is to alter radioStreamURL variable.

private String radioStreamURL = MainActivity.radioStreamURL;

If you have some static information about the radios you want to use, just change this String to a List and add all the Radio's URL you want.

Add a Next and Preview button to your layout, set the listener to call your RadioService with this function, something like this:

MainActivity

private static int station = 0;//Not right, just to show

public void onNextStationClicked(){
    radioServiceBinder.changeStation(++station);
}

RadioService

public static final String MODE_STATION_CHANGE = "STATION_CHANGE";

public void changeStation(int stationIndex){
  radioStreamURL = MainActivity.radioStreamURL.get(stationIndex);
  stop();
  play();
}

This is just an idea, the code isn't the best but with a little work should work...

UPDATE

Try change your code to this:

RadioService

private List<String> radioStreamURL = new ArrayList<String>
private int radioStreamingIndex = 0;

then on your constructor add this

@Override
    public void onCreate() {
    radioStreamURL.add(radioStreamURL);
    radioStreamURL.add(radioStreamURL2);
    radioStreamURL.add(radioStreamURL3);
    // etc
}
 public void prepare() {     
        /* Prepare Async Task - starts buffering */
        try {           
            mediaPlayer.setDataSource(radioStreamURL.get(radioStreamingIndex));
            mediaPlayer.prepareAsync();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

public void nextStation(){
  changeStation(radioStreamingIndex+1);
}

public void prevStation(){
  changeStation(radioStreamingIndex-1);
}

private void changeStation(int stationIndex){
  if(stationIndex > 0 && stationIndex < radioStreamURL.size()){
  radioStreamingIndex = stationIndex;
  stop();
  play();
  }
}

MainActivity

nextButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        radioServiceBinder.nextStation();
    }
});

prevButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        radioServiceBinder.prevStation();
    }
});

Upvotes: 3

Related Questions