Tistory View

지난번 포스트에서 접근 권한의 문제로 인해 알림음 재생에 실패했다. 하지만 Android에서는 API 1부터 지원하는 Ringtone이라는 class가 있다. 이 것을 이용하면 지난번 문제를 해결할 수 있다.

지난번 포스트 : 안드로이드 알림음 선택 / 알림음 재생하기 #1

 

 

MediaPlayer instance대신 Ringtone instance로 교체하는 코드를 작성해 보자

추가되는 멤버 변수 부분

public class MainActivity extends AppCompatActivity
implements View.OnClickListener
{
    private final static String TAG = "MainActivity";

    private final static int REQUESTCODE_RINGTONE_PICKER = 1000;


    // 이전 문제의 버전에서 재생을 위해 사용했던 MediaPlayer
    //private MediaPlayer mMediaPlayer;

    // 문제 해결을 위해 Ringtone으로 변경
    private RingtoneManager mRtm;
    // 현재 재생중인 링톤
    private Ringtone mRtCurrent;



    // View cache
    private TextView m_tvRingtoneUri;

    // Ringtone class는 제목을 구할 수 있어서 TextView를 더 추가 했다.
    private TextView m_tvRingtoneTitle;
    private String   m_strRingToneUri;
    .
    .
    .

MediaPlayer로 재생하던 것을 Ringtone으로 바꾸는 코드다. Ringtone instance를 만드려면 RingtoneManager가 필요하니 멤버변수로 만들어 둔다. 또 추가된 것은 Ringtone은 제목을 추출할 수가 있다. Ringtone instance가 잘 동작하는지 확인하기위해 간단히 추가된 TextView일 뿐이다. 이 TextView로 인해 레이아웃파일이 변경되는 데, 이 코드는 전체코드에 있다.

 

재생을 중지하는 함수

 //-- 재생중인 링톤을 중지하는 함수
    private void releaseRingtone()
    {
        /*
        if( mMediaPlayer != null )
        {
            if( mMediaPlayer.isPlaying() ) {
                mMediaPlayer.stop();
            }
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
        */

        if( mRtCurrent != null )
        {
            if( mRtCurrent.isPlaying() ) {
                mRtCurrent.stop();
                mRtCurrent = null;
            }
        }



        m_tvRingtoneUri.setText("Choose Ringtone");
        m_tvRingtoneTitle.setText("");
    }

MediaPlayer에서 Ringtone으로 변경하였다.

 

 

play부분

//-- 링톤을 재생하는 함수
    private void startRingtone( Uri uriRingtone )
    {
        this.releaseRingtone();

        try {
            mRtCurrent = mRtm.getRingtone( this, uriRingtone );

            if( mRtCurrent == null ) {
                throw new Exception("Can't play ringtone");
            }

            m_tvRingtoneUri.setText( uriRingtone.toString() );
            m_tvRingtoneTitle.setText( mRtCurrent.getTitle( this ) );

            mRtCurrent.play();
        }
        catch( Exception e ) {
            Toast.makeText( this, e.getMessage(), Toast.LENGTH_SHORT ).show();
            Log.e(TAG, e.getMessage() );
            e.printStackTrace();
        }
    }

RingtoneManager로 부터 Ringtone을 가져와서 Ringtone instance에서 바로 재생한다. 혹시나 모를 오류가 있을 지 몰라 null체크를 했다. getRingtone함수는 넘긴 uri값이 문제가 있거나 파일을 없거나 하면 기본음을 돌려준다고 되어 있어서 추가적으로 실패시 기본음을 가져오는 코드를 작성할 필요가 없다.

 

선택창에서 넘어온 데이터 처리

//-- 알림선택창에서 넘어온 데이터를 처리하는 코드
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if( requestCode == REQUESTCODE_RINGTONE_PICKER )
        {
            if (resultCode == RESULT_OK)
            {
                // -- 알림음 재생하는 코드 -- //
                Uri ring = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);


                if (ring != null) {

                    m_strRingToneUri = ring.toString();
                    m_tvRingtoneUri.setText( ring.toString() );

                    this.startRingtone( ring );

                } else {
                    m_strRingToneUri = null;
                    m_tvRingtoneUri.setText( "Choose ringtone" );
                    m_tvRingtoneTitle.setText("");
                }
            }
        }
    }

특별히 바뀐 것은 없고 TextView의 내용을 바꾸는 코드가 전부이다.

 

잘 된다.

 

여기까지 처리하면 Dangerous Permission인 [READ_EXTERNAL_STORAGE]권한 없이 재생이 가능하다.

필자의 경우 음악의 길이를 알아오는 코드가 필요해서 이제까지 작성한 코드가 필요없어 졌지만, 단순히 재생하는 일만 있다면 문제없이 사용이 가능해 보인다.

지난번 포스트에서 언급해던 문제인 이 방식[Ringtone]을 이용하면, 일부기기(샤오미 pocophone F1)의 경우, 기기내에 존재하는 거의 모든 파일을 재생할 수 있을 지도 모른다. 테스트를 해 보겠지만 테스트 결과에 따라 추가적인 포스트가 있을 수 있다. 이 문제가 문제가 되는 부분은 통화내용 녹음파일을 일부러 재생 해버리는 등에 문제가 발생할 수도 있다.

 

끝~

 

 

activity_main.xml 전체

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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=".MainActivity">


    <TextView
        android:id="@+id/ringtone_uri"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Choose ringtone"

        />

    <TextView
        android:id="@+id/ringtone_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=""
        android:layout_below="@+id/ringtone_uri"
        />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"

        android:layout_alignParentBottom="true">

        <android.support.v7.widget.AppCompatButton
            android:id="@+id/show_ringtone_chooser"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="알림선택창띄우기"


            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            />

        <android.support.v7.widget.AppCompatButton
            android:id="@+id/stop_play_ringtone"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="조용히해~"

            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"

            />
    </RelativeLayout>

</RelativeLayout>

 

MainActivity.java 전체

package a.b.c.playringtone;

import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity
implements View.OnClickListener
{
    private final static String TAG = "MainActivity";

    private final static int REQUESTCODE_RINGTONE_PICKER = 1000;


    // 이전 문제의 버전에서 재생을 위해 사용했던 MediaPlayer
    //private MediaPlayer mMediaPlayer;

    // 문제 해결을 위해 Ringtone으로 변경
    private RingtoneManager mRtm;
    // 현재 재생중인 링톤
    private Ringtone mRtCurrent;



    // View cache
    private TextView m_tvRingtoneUri;

    // Ringtone class는 제목을 구할 수 있어서 TextView를 더 추가 했다.
    private TextView m_tvRingtoneTitle;
    private String   m_strRingToneUri;

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

        mRtm = new RingtoneManager( this );

        m_tvRingtoneUri   = this.findViewById( R.id.ringtone_uri );
        m_tvRingtoneTitle = this.findViewById( R.id.ringtone_title );

        this.findViewById( R.id.show_ringtone_chooser ).setOnClickListener( this );
        this.findViewById( R.id.stop_play_ringtone    ).setOnClickListener( this );

    }

    //-- 링톤을 재생하는 함수
    private void startRingtone( Uri uriRingtone )
    {
        this.releaseRingtone();

        try {
            mRtCurrent = mRtm.getRingtone( this, uriRingtone );

            if( mRtCurrent == null ) {
                throw new Exception("Can't play ringtone");
            }

            m_tvRingtoneUri.setText( uriRingtone.toString() );
            m_tvRingtoneTitle.setText( mRtCurrent.getTitle( this ) );

            mRtCurrent.play();
        }
        catch( Exception e ) {
            Toast.makeText( this, e.getMessage(), Toast.LENGTH_SHORT ).show();
            Log.e(TAG, e.getMessage() );
            e.printStackTrace();
        }
    }

    //-- 재생중인 링톤을 중지하는 함수
    private void releaseRingtone()
    {
        /*
        if( mMediaPlayer != null )
        {
            if( mMediaPlayer.isPlaying() ) {
                mMediaPlayer.stop();
            }
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
        */

        if( mRtCurrent != null )
        {
            if( mRtCurrent.isPlaying() ) {
                mRtCurrent.stop();
                mRtCurrent = null;
            }
        }



        m_tvRingtoneUri.setText("Choose Ringtone");
        m_tvRingtoneTitle.setText("");
    }

    //-- 기본 알림창을 띄우기 위한 Intent생성
    //-- 기본 알림선택창을 띄우고 결과를 받아와야 하기 때문에 startActivityForResult를 써야한다.
    private void showRingtonChooser() {

        Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);

        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, "Choose Ringtone!" );
        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT,  false);
        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);

        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_ALL);

        //-- 알림 선택창이 떴을 때, 기본값으로 선택되어질 ringtone설정
        if( m_strRingToneUri != null && m_strRingToneUri.isEmpty() )
        {
            intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Uri.parse( m_strRingToneUri ));
        }

        this.startActivityForResult( intent, REQUESTCODE_RINGTONE_PICKER );
    }

    //-- 알림선택창에서 넘어온 데이터를 처리하는 코드
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if( requestCode == REQUESTCODE_RINGTONE_PICKER )
        {
            if (resultCode == RESULT_OK)
            {
                // -- 알림음 재생하는 코드 -- //
                Uri ring = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);


                if (ring != null) {

                    m_strRingToneUri = ring.toString();
                    m_tvRingtoneUri.setText( ring.toString() );

                    this.startRingtone( ring );

                } else {
                    m_strRingToneUri = null;
                    m_tvRingtoneUri.setText( "Choose ringtone" );
                    m_tvRingtoneTitle.setText("");
                }
            }
        }
    }


    //-- 눌러진 버튼에 따라 처리하는 함수
    @Override
    public void onClick(View v) {

        switch( v.getId() ) {
            case R.id.show_ringtone_chooser:
                showRingtonChooser();
                break;
            case R.id.stop_play_ringtone:
                this.releaseRingtone();
                break;
        }
    }
}

 

 


 

Replies
Reply Write