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;
}
}
}
'Android Note' 카테고리의 다른 글
MediaPlayer and Ringtone : setAudioStreamType and setAudioAttributes (0) | 2019.06.03 |
---|---|
안드로이드 알림음 선택 / 알림음 재생하기 #1 - 반정도 실패한 이야기 (3) | 2019.06.01 |
안드로이드 전화통화상태 받기 (0) | 2016.07.07 |
구글플레이서비스 V29 업데이트 후 admob이 보이지가 않는다. (0) | 2016.05.30 |
- Total
- Today
- Yesterday
- Android
- 컴퓨트셰이더
- OpenGLes
- 재태크
- 금리
- texture
- 사용료
- 안드로이드
- 전기세
- gpgpu
- 예금
- 컴퓨트쉐이더
- 재테크
- 전기료
- 텍스처
- 블로그
- 에어컨
- OpenGL ES
- choreographer
- TTS
- 경제보복
- 전기요금
- 에어콘
- 애드핏
- 티스토리
- 적금
- 공유 컨텍스트
- 아끼는 법
- ComputeShader
- 애드센스
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |