1 /* 2 * Copyright 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.mediasession.service; 18 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.media.AudioManager; 24 import android.net.wifi.WifiManager; 25 import android.support.annotation.NonNull; 26 import android.support.v4.media.MediaMetadataCompat; 27 import android.support.v4.media.session.PlaybackStateCompat; 28 29 /** 30 * Abstract player implementation that handles playing music with proper handling of headphones 31 * and audio focus. 32 */ 33 public abstract class PlayerAdapter { 34 35 private static final float MEDIA_VOLUME_DEFAULT = 1.0f; 36 private static final float MEDIA_VOLUME_DUCK = 0.2f; 37 38 private static final IntentFilter AUDIO_NOISY_INTENT_FILTER = 39 new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY); 40 41 private boolean mAudioNoisyReceiverRegistered = false; 42 private final BroadcastReceiver mAudioNoisyReceiver = 43 new BroadcastReceiver() { 44 @Override 45 public void onReceive(Context context, Intent intent) { 46 if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) { 47 if (isPlaying()) { 48 pause(); 49 } 50 } 51 } 52 }; 53 54 private final Context mApplicationContext; 55 private final AudioManager mAudioManager; 56 private final AudioFocusHelper mAudioFocusHelper; 57 58 private boolean mPlayOnAudioFocus = false; 59 60 public PlayerAdapter(@NonNull Context context) { 61 mApplicationContext = context.getApplicationContext(); 62 mAudioManager = (AudioManager) mApplicationContext.getSystemService(Context.AUDIO_SERVICE); 63 mAudioFocusHelper = new AudioFocusHelper(); 64 } 65 66 public abstract void playFromMedia(MediaMetadataCompat metadata); 67 68 public abstract MediaMetadataCompat getCurrentMedia(); 69 70 public abstract boolean isPlaying(); 71 72 public final void play() { 73 if (mAudioFocusHelper.requestAudioFocus()) { 74 registerAudioNoisyReceiver(); 75 onPlay(); 76 } 77 } 78 79 /** 80 * Called when media is ready to be played and indicates the app has audio focus. 81 */ 82 protected abstract void onPlay(); 83 84 public final void pause() { 85 if (!mPlayOnAudioFocus) { 86 mAudioFocusHelper.abandonAudioFocus(); 87 } 88 89 unregisterAudioNoisyReceiver(); 90 onPause(); 91 } 92 93 /** 94 * Called when media must be paused. 95 */ 96 protected abstract void onPause(); 97 98 public final void stop() { 99 mAudioFocusHelper.abandonAudioFocus(); 100 unregisterAudioNoisyReceiver(); 101 onStop(); 102 } 103 104 /** 105 * Called when the media must be stopped. The player should clean up resources at this 106 * point. 107 */ 108 protected abstract void onStop(); 109 110 public abstract void seekTo(long position); 111 112 public abstract void setVolume(float volume); 113 114 private void registerAudioNoisyReceiver() { 115 if (!mAudioNoisyReceiverRegistered) { 116 mApplicationContext.registerReceiver(mAudioNoisyReceiver, AUDIO_NOISY_INTENT_FILTER); 117 mAudioNoisyReceiverRegistered = true; 118 } 119 } 120 121 private void unregisterAudioNoisyReceiver() { 122 if (mAudioNoisyReceiverRegistered) { 123 mApplicationContext.unregisterReceiver(mAudioNoisyReceiver); 124 mAudioNoisyReceiverRegistered = false; 125 } 126 } 127 128 /** 129 * Helper class for managing audio focus related tasks. 130 */ 131 private final class AudioFocusHelper 132 implements AudioManager.OnAudioFocusChangeListener { 133 134 private boolean requestAudioFocus() { 135 final int result = mAudioManager.requestAudioFocus(this, 136 AudioManager.STREAM_MUSIC, 137 AudioManager.AUDIOFOCUS_GAIN); 138 return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 139 } 140 141 private void abandonAudioFocus() { 142 mAudioManager.abandonAudioFocus(this); 143 } 144 145 @Override 146 public void onAudioFocusChange(int focusChange) { 147 switch (focusChange) { 148 case AudioManager.AUDIOFOCUS_GAIN: 149 if (mPlayOnAudioFocus && !isPlaying()) { 150 play(); 151 } else if (isPlaying()) { 152 setVolume(MEDIA_VOLUME_DEFAULT); 153 } 154 mPlayOnAudioFocus = false; 155 break; 156 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 157 setVolume(MEDIA_VOLUME_DUCK); 158 break; 159 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 160 if (isPlaying()) { 161 mPlayOnAudioFocus = true; 162 pause(); 163 } 164 break; 165 case AudioManager.AUDIOFOCUS_LOSS: 166 mAudioManager.abandonAudioFocus(this); 167 mPlayOnAudioFocus = false; 168 stop(); 169 break; 170 } 171 } 172 } 173 } 174