publicvoidrequestAudioFocus(){ Log.d(TAG, "AudioFocus >> called requestAudioFocus() / Build.VERSION: " + Build.VERSION.SDK_INT); // TODO: 2. Build.VERSION_CODES.O 미만 단말에서의 AudioFocus Request 기능 추가 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Log.d(TAG, "AudioFocus >> requestAudioFocus"); audioManager.requestAudioFocus(audioFocusRequest); } } // TODO: 3. abandonAudioFocus() function 추가
@Override publicvoidonAudioFocusChange(int focusChange){ switch (focusChange) { case AudioManager.AUDIOFOCUS_GAIN: // 이제부터 AudioFocus는 우리 앱의 소유! Log.d(TAG, "AudioFocus >> AUDIOFOCUS_GAIN"); break; case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT: // 일시적으로 AudioFocus를 가져온다. Log.d(TAG, "AudioFocus >> AUDIOFOCUS_GAIN_TRANSIENT"); break; case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK: // 15초 이상 점유하면 안 된다. 앱의 소리가 나지만, Background App의 사운드가 작게 들릴 수 있다. Log.d(TAG, "AudioFocus >> AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK"); break; case AudioManager.AUDIOFOCUS_LOSS: Log.d(TAG, "AudioFocus >> AUDIOFOCUS_LOSS"); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: // 일시적인 LOSS로, 잠깐 사용한 App이 점유를 끝내면 가장 마지막에 GAIN한 App이 AudioFocus를 점유한다. Log.d(TAG, "AudioFocus >> AUDIOFOCUS_LOSS_TRANSIENT"); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // 볼륨을 낮추는 것을 권장한다. Log.d(TAG, "AudioFocus >> AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK"); break; case AudioManager.AUDIOFOCUS_REQUEST_FAILED: // 요청 실패할 경우의 로직을 추가한다. Log.d(TAG, "AudioFocus >> AUDIOFOCUS_REQUEST_FAILED"); break; } } }
1번부터 3번까지의 TODO를 추가해 보았다. 1번부터 천천히 수정해 보자.
1. Build.VERSION_CODES.O 미만인 단말에서의 생성자 세팅 추가
이 코드는 아주 간단하다. Build.VERSION_CODES.O 미만인 단말에서는 AudioManager 생성만 해 주면 된다. 그래서 별도의 else 처리 없이, if 문 안에 있던 AudioManager 를 밖으로 빼 준다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
publicAudioFocusHelper(@Nonnull Context context){ Log.d(TAG, "Create AudioFocusHelper"); // 이렇게 위로 빼 주면 됨 audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); AudioAttributes mAudioAttributes = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build(); audioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) .setAudioAttributes(mAudioAttributes) .setAcceptsDelayedFocusGain(true) .setOnAudioFocusChangeListener(this) .setWillPauseWhenDucked(true) .build(); } }
2. Build.VERSION_CODES.O 미만 단말에서의 AudioFocus Request 기능 추가
Oreo, API level 26보다 낮은 단말에서 AudioFocus 를 얻고 싶다면 다음의 코드를 사용하자.
1 2 3 4 5 6 7 8 9
publicvoidrequestAudioFocus(){ Log.d(TAG, "AudioFocus >> called requestAudioFocus() / Build.VERSION: " + Build.VERSION.SDK_INT); // TODO: 2. Build.VERSION_CODES.O 미만 단말에서의 AudioFocus Request 기능 추가 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { audioManager.requestAudioFocus(audioFocusRequest); } else { audioManager.requestAudioFocus(this, AudioManager.USE_DEFAULT_STREAM_TYPE, AudioManager.AUDIOFOCUS_GAIN); } }
requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) 형태를 따라 적절한 값을 넣어 주면 된다.
3. abandonAudioFocus() function 추가
앞서 우리는 AudioFocus 를 요청만 했지 반납하지 않았다. 서비스가 종료되거나, 더이상의 Audio가 필요하지 않을 땐 AudioFocus 를 반납하는 것이 인지상정! 이 코드도 굉장히 짧다.
1 2 3 4 5 6 7 8
publicvoidabandonAudioFocus(){ Log.d(TAG, "AudioFocus >> called abandonAudioFocus()"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { audioManager.abandonAudioFocusRequest(audioFocusRequest); } else { audioManager.abandonAudioFocus(this); } }
너무 쉽죠?
전체 코드 보기
Oreo 미만 단말에서 AudioFocus 를 요청할 수 있고, 반납 기능이 추가된 AudioFocusHelper.java 코드 전체는 다음과 같다.
@Override publicvoidonAudioFocusChange(int focusChange){ switch (focusChange) { case AudioManager.AUDIOFOCUS_GAIN: // 이제부터 AudioFocus는 우리 앱의 소유! Log.d(TAG, "AudioFocus >> AUDIOFOCUS_GAIN"); break; case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT: // 일시적으로 AudioFocus를 가져온다. Log.d(TAG, "AudioFocus >> AUDIOFOCUS_GAIN_TRANSIENT"); break; case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK: // 15초 이상 점유하면 안 된다. 앱의 소리가 나지만, Background App의 사운드가 작게 들릴 수 있다. Log.d(TAG, "AudioFocus >> AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK"); break; case AudioManager.AUDIOFOCUS_LOSS: Log.d(TAG, "AudioFocus >> AUDIOFOCUS_LOSS"); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: // 일시적인 LOSS로, 잠깐 사용한 App이 점유를 끝내면 가장 마지막에 GAIN한 App이 AudioFocus를 점유한다. Log.d(TAG, "AudioFocus >> AUDIOFOCUS_LOSS_TRANSIENT"); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // 볼륨을 낮추는 것을 권장한다. Log.d(TAG, "AudioFocus >> AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK"); break; case AudioManager.AUDIOFOCUS_REQUEST_FAILED: // 요청 실패할 경우의 로직을 추가한다. Log.d(TAG, "AudioFocus >> AUDIOFOCUS_REQUEST_FAILED"); break; } } }
위의 코드에서 나는 OnAudioFocusChangeListener 를 implement 하여 구현하였지만, class 내에서 직접 new 로 선언해 주어도 문제가 되지 않는다. 이전 코드는 그런 형식으로 되어 있었는데, implement 하는 방식이 더 깔끔하게 구현될 것 같아서 약간의 리팩토링 과정을 거쳐 수정하였다. 아무튼, 이대로 싱겁게 이번 포스팅 끝!