Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b8ea1f93 authored by Scott Main's avatar Scott Main Committed by Android Git Automerger
Browse files

am 4dc763c7: Merge "doc change: Android U lessons for audio and battery" into ics-mr0

* commit '4dc763c7':
  doc change: Android U lessons for audio and battery
parents 691fea72 4dc763c7
Loading
Loading
Loading
Loading
+183 −0
Original line number Diff line number Diff line
page.title=Managing Audio Focus
parent.title=Managing Audio Playback and Focus
parent.link=index.html

trainingnavtop=true
previous.title=Controlling Your App's Volume and Playback
previous.link=volume-playback.html
next.title=Dealing with Audio Output Hardware
next.link=audio-output.html

@jd:body


<div id="tb-wrapper"> 
<div id="tb">

<h2>This lesson teaches you to</h2>
<ol>
  <li><a href="#RequestFocus">Request the Audio Focus</a></li>
  <li><a href="#HandleFocusLoss">Handle the Loss of Audio Focus</a></li>
  <li><a href="#DUCK">Duck!</a></li>
</ol>


<h2>You should also read</h2>
<ul>
  <li><a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a></li>
</ul>

</div> 
</div>
 

<p>With multiple apps potentially playing audio it's important to think about how they should
interact. To avoid every music app playing at the same time, Android uses audio focus to moderate
audio playback&mdash;only apps that hold the audio focus should play audio.</p>

<p>Before your app starts playing audio it should request&mdash;and receive&mdash;the audio focus. 
Likewise, it should know how to listen for a loss of audio focus and respond appropriately when that
happens.</p>

 
<h2 id="RequestFocus">Request the Audio Focus</h2> 
 
<p>Before your app starts playing any audio, it should hold the audio focus for the stream
it will be using. This is done with a call to {@link android.media.AudioManager#requestAudioFocus
requestAudioFocus()} which returns
{@link android.media.AudioManager#AUDIOFOCUS_REQUEST_GRANTED} if your request is successful.</p>

<p>You must specify which stream you're using and whether you expect to require transient or
permanent audio focus. Request transient focus when you expect to play audio for only a short time
(for example when playing navigation instructions). Request permanent audio focus when you
plan to play audio for the foreseeable future (for example, when playing music).</p>

<p>The following snippet requests permanent audio focus on the music audio stream. You should
request the audio focus immediately before you begin playback, such as when the user presses
play or the background music for the next game level begins.</p>
  
<pre>
AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...

// Request audio focus for playback
int result = am.requestAudioFocus(afChangeListener,
                                 // Use the music stream.
                                 AudioManager.STREAM_MUSIC,
                                 // Request permanent focus.
                                 AudioManager.AUDIOFOCUS_GAIN);
   
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
    // Start playback.
}
</pre>

<p>Once you've finished playback be sure to call {@link
android.media.AudioManager#abandonAudioFocus abandonAudioFocus()}. This notifies
the system that you no longer require focus and unregisters the associated {@link
android.media.AudioManager.OnAudioFocusChangeListener}. In the case of abandoning transient focus,
this allows any interupted app to continue playback.</p>

<pre>
// Abandon audio focus when playback complete    
am.abandonAudioFocus(afChangeListener);
</pre>

<p>When requesting transient audio focus you have an additional option: whether or not you want to
enable "ducking." Normally, when a well-behaved audio app loses audio focus it immediately
silences its playback. By requesting a transient audio focus that allows ducking you tell other
audio apps that it’s acceptable for them to keep playing, provided they lower their volume until the
focus returns to them.</p>

<pre>
// Request audio focus for playback
int result = am.requestAudioFocus(afChangeListener,
                             // Use the music stream.
                             AudioManager.STREAM_MUSIC,
                             // Request permanent focus.
                             AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
   
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    // Start playback.
}
</pre>

<p>Ducking is particularly suitable for apps that use the audio stream intermittently, such as for
audible driving directions.</p>

<p>Whenever another app requests audio focus as described above, its choice between permanent and
transient (with or without support for ducking) audio focus is received by the listener you
registered when requesting focus.</p>


<h2 id="HandleFocusLoss">Handle the Loss of Audio Focus</h2> 

<p>If your app can request audio focus, it follows that it will in turn lose that focus when another
app requests it. How your app responds to a loss of audio focus depends on the manner of that
loss.</p>

<p>The {@link android.media.AudioManager.OnAudioFocusChangeListener#onAudioFocusChange
onAudioFocusChange()} callback method of they audio focus change listener you registered when
requesting audio focus receives a parameter that describes the focus change event. Specifically,
the possible focus loss events mirror the focus request types from the previous
section&mdash;permanent loss, transient loss, and transient with ducking permitted.</p>

<p>Generally speaking, a transient (temporary) loss of audio focus should result in your app
silencing it’s audio stream, but otherwise maintaining the same state. You should continue to
monitor changes in audio focus and be prepared to resume playback where it was paused once you’ve
regained the focus.</p>

<p>If the audio focus loss is permanent, it’s assumed that another application is now being used to
listen to audio and your app should effectively end itself. In practical terms, that means stopping
playback, removing media button listeners&mdash;allowing the new audio player to exclusively handle
those events&mdash;and abandoning your audio focus. At that point, you would expect a user action
(pressing play in your app) to be required before you resume playing audio.</p>

<p>In the following code snippet, we pause the playback or our media player object if the audio
loss is transien and resume it when we have regained the focus. If the loss is permanent, it
unregisters our media button event receiver and stops monitoring audio focus changes.<p>

<pre>
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
    public void onAudioFocusChange(int focusChange) {
        if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT
            // Pause playback
        } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
            // Resume playback 
        } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
            am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
            am.abandonAudioFocus(afChangeListener);
            // Stop playback
        }
    }
};
</pre>
 
<p>In the case of a transient loss of audio focus where ducking is permitted, rather than pausing
playback, you can "duck" instead.</p>


<h2 id="DUCK">Duck!</h2> 

<p>Ducking is the process of lowering your audio stream output volume to make transient audio from
another app easier to hear without totally disrupting the audio from your own application.</p>

<p>In the following code snippet lowers the volume on our media player object when we temporarily
lose focus, then returns it to its previous level when we regain focus.</p>

<pre>
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
    public void onAudioFocusChange(int focusChange) {
        if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
            // Lower the volume
        } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
            // Raise it back to normal
        }
    }
};
</pre>

<p>A loss of audio focus is the most important broadcast to react to, but not the only one. The
system broadcasts a number of intents to alert you to changes in user’s audio experience.
The next lesson demonstrates how to monitor them to improve the user’s overall experience.</p>
+88 −0
Original line number Diff line number Diff line
page.title=Dealing with Audio Output Hardware
parent.title=Managing Audio Playback and Focus
parent.link=index.html

trainingnavtop=true
previous.title=Managing Audio Focus
previous.link=audio-focus.html

@jd:body

 
<div id="tb-wrapper"> 
<div id="tb">

<h2>This lesson teaches you to</h2>
<ol>
  <li><a href="#CheckHardware">Check What Hardware is Being Used</a></li>
  <li><a href="#HandleChanges">Handle Changes in the Audio Output Hardware</a></li>
</ol>


<h2>You should also read</h2>
<ul>
  <li><a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a></li>
</ul>


</div> 
</div>

<p>Users have a number of alternatives when it comes to enjoying the audio from their Android
devices. Most devices have a built-in speaker, headphone jacks for wired headsets, and many also
feature Bluetooth connectivity and support for A2DP audio. </p>

 
<h2 id="CheckHardware">Check What Hardware is Being Used</h2> 
 
<p>How your app behaves might be affected by which hardware its output is being routed to.</p>

<p>You can query the {@link android.media.AudioManager} to determine if the audio is currently
being routed to the device speaker, wired headset, or attached Bluetooth device as shown in the
following snippet:</p>

<pre>
if (isBluetoothA2dpOn()) {
    // Adjust output for Bluetooth.
} else if (isSpeakerphoneOn()) {
    // Adjust output for Speakerphone.
} else if (isWiredHeadsetOn()) {
    // Adjust output for headsets
} else { 
    // If audio plays and noone can hear it, is it still playing?
}
</pre>


<h2 id="HandleChanges">Handle Changes in the Audio Output Hardware</h2> 

<p>When a headset is unplugged, or a Bluetooth device disconnected, the audio stream
automatically reroutes to the built in speaker. If you listen to your music at as high a volume as I
do, that can be a noisy surprise.</p>

<p>Luckily the system broadcasts an {@link android.media.AudioManager#ACTION_AUDIO_BECOMING_NOISY}
intent when this happens. It’s good practice to register a {@link android.content.BroadcastReceiver}
that listens for this intent whenever you’re playing audio. In the case of music players, users
typically expect the playback to be paused&mdash;while for games you may choose to significantly
lower the volume.</p>
 
<pre>
private class NoisyAudioStreamReceiver extends BroadcastReceiver {
    &#64;Override
    public void onReceive(Context context, Intent intent) {
        if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
            // Pause the playback
        }
    }
}

private IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);

private void startPlayback() {
    registerReceiver(myNoisyAudioStreamReceiver(), intentFilter);
}

private void stopPlayback() {
    unregisterReceiver(myNoisyAudioStreamReceiver);
}
</pre>
+62 −0
Original line number Diff line number Diff line
page.title=Managing Audio Playback and Focus

trainingnavtop=true
startpage=true
next.title=Controlling Your App's Volume and Playback
next.link=volume-playback.html

@jd:body

<div id="tb-wrapper"> 
<div id="tb">

<h2>Dependencies and prerequisites</h2> 
<ul>
  <li>Android 2.0 (API level 5) or higher</li>
  <li>Experience with <a href="{@docRoot}guide/topics/media/mediaplayer.html">Media
Playback</a></li>
</ul>

<h2>You should also read</h2>
<ul>
  <li><a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a></li>
</ul>

</div> 
</div>


<p>If your app plays audio, it’s important that your users can control the audio in a predictable
manner. To ensure a great user experience, it’s also important that your app manages the audio focus
to ensure multiple apps aren’t playing audio at the same time.</p> 

<p>After this class, you will be able to build apps that respond to hardware audio key presses, 
which request audio focus when playing audio, and which respond appropriately to changes in audio
focus caused by the system or other applications.</p> 




<h2>Lessons</h2> 
 
<!-- Create a list of the lessons in this class along with a short description of each lesson.
These should be short and to the point. It should be clear from reading the summary whether someone
will want to jump to a lesson or not.--> 
 
<dl>
  <dt><b><a href="volume-playback.html">Controlling Your App’s Volume and
Playback</a></b></dt>
  <dd>Learn how to ensure your users can control the volume of your app using the hardware or
software volume controls and where available the play, stop, pause, skip, and previous media
playback keys.</dd> 
 
  <dt><b><a href="audio-focus.html">Managing Audio Focus</a></b></dt>
  <dd>With multiple apps potentially playing audio it's important to think about how they should
interact. To avoid every music app playing at the same time, Android uses audio focus to moderate
audio playback. Learn how to request the audio focus, listen for a loss of audio focus, and how to
respond when that happens.</dd> 
 
  <dt><b><a href="audio-output.html">Dealing with Audio Output Hardware</a></b></dt>
  <dd>Audio can be played from a number of sources. Learn how to find out where the audio is being
played and how to handle a headset being disconnected during playback.</dd> 
 </dl> 
 No newline at end of file
+156 −0
Original line number Diff line number Diff line
page.title=Controlling Your App’s Volume and Playback
parent.title=Managing Audio Playback and Focus
parent.link=index.html

trainingnavtop=true
next.title=Managing Audio Focus
next.link=audio-focus.html

@jd:body

 
<div id="tb-wrapper"> 
<div id="tb">

<h2>This lesson teaches you to</h2>
<ol>
  <li><a href="#IdentifyStream">Identify Which Audio Stream to Use</a></li>
  <li><a href="#HardwareVolumeKeys">Use Hardware Volume Keys to Control Your App’s Audio
Volume</a></li>
  <li><a href="#PlaybackControls">Use Hardware Playback Control Keys to Control Your App’s Audio
Playback</a></li>
</ol>

<h2>You should also read</h2>
<ul>
  <li><a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a></li>
</ul>

</div> 
</div>


 
<p>A good user experience is a predictable one. If your app plays media it’s important that your
users can control the volume of your app using the hardware or software volume controls of their
device, bluetooth headset, or headphones.</p>

<p>Similarly, where appropriate and available, the play, stop, pause, skip, and previous media
playback keys should perform their respective actions on the audio stream used by your app.</p>

 
<h2 id="IdentifyStream">Identify Which Audio Stream to Use</h2> 
 
<p>The first step to creating a predictable audio experience is understanding which audio stream
your app will use.</p>

<p>Android maintains a separate audio stream for playing music, alarms, notifications, the incoming
call ringer, system sounds, in-call volume, and DTMF tones. This is done primarily to allow users to
control the volume of each stream independently.</p>

<p>Most of these streams are restricted to system events, so unless your app is a replacement alarm
clock, you’ll almost certainly be playing your audio using the {@link
android.media.AudioManager#STREAM_MUSIC} stream.</p>


<h2 id="HardwareVolumeKeys">Use Hardware Volume Keys to Control Your App’s Audio Volume</h2> 

<p>By default, pressing the volume controls modify the volume of the active audio stream. If your
app isn't currently playing anything, hitting the volume keys adjusts the ringer volume.<p>
    
<p>If you've got a game or music app, then chances are good that when the user hits the volume keys
they want to control the volume of the game or music, even if they’re currently between songs or
there’s no music in the current game location.</p>

<p>You may be tempted to try and listen for volume key presses and modify the volume of your
audio stream that way. Resist the urge. Android provides the handy {@link
android.app.Activity#setVolumeControlStream setVolumeControlStream()} method to direct volume key
presses to the audio stream you specify.<p> 
  
<p>Having identified the audio stream your application
will be using, you should set it as the volume stream target. You should make this call early in
your app’s lifecycle&mdash;because you only need to call it once during the activity lifecycle, you
should typically call it within the {@code onCreate()} method (of the {@link
android.app.Activity} or {@link android.app.Fragment} that controls
your media). This ensures that whenever your app is visible, the
volume controls function as the user expects.<p>

<pre>
setVolumeControlStream(AudioManager.STREAM_MUSIC);
</pre>


<p>From this point onwards, pressing the volume keys on the device affect the audio stream you
specify (in this case “music”) whenever the target activity or fragment is visible.</p>


<h2 id="PlaybackControls">Use Hardware Playback Control Keys to Control Your App’s Audio
Playback</h2> 

<p>Media playback buttons such as play, pause, stop, skip, and previous are available on some
handsets and many connected or wireless headsets. Whenever a user presses one of these hardware
keys, the system broadcasts an intent with the {@link android.content.Intent#ACTION_MEDIA_BUTTON}
action.</p>

<p>To respond to media button clicks, you need to register a {@link
android.content.BroadcastReceiver} in your manifest that listens for this action broadcast as shown
below.</p>

<pre>
&lt;receiver android:name=".RemoteControlReceiver">
    &lt;intent-filter>
        &lt;action android:name="android.intent.action.MEDIA_BUTTON" />
    &lt;/intent-filter>
&lt;/receiver>
</pre>

<p>The receiver implementation itself needs to extract which key was pressed to cause the broadcast.
The {@link android.content.Intent} includes this under the {@link
android.content.Intent#EXTRA_KEY_EVENT} key, while the {@link android.view.KeyEvent} class includes
a list {@code KEYCODE_MEDIA_*} static constants that represents each of the possible media
buttons, such as {@link android.view.KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE} and {@link
android.view.KeyEvent#KEYCODE_MEDIA_NEXT}.</p>

<p>The following snippet shows how to extract the media button pressed and affects the media playback accordingly.</p>

<pre>
public class RemoteControlReceiver extends BroadcastReceiver {
    &#64;Override
    public void onReceive(Context context, Intent intent) {
        if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
            KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
            if (KeyEvent.KEYCODE_MEDIA_PLAY == event.getKeyCode()) {
                // Handle key press.
            }
        }
    }
}
</pre>

<p>Because multiple applications might want to listen for media button presses, you must
also programmatically control when your app should receive media button press events.</p>

<p>The following code can be used within your app to register and de-register your media button
event receiver using the {@link android.media.AudioManager}. When registered, your broadcast
receiver is the exclusive receiver of all media button broadcasts.<p>

<pre>
AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...

// Start listening for button presses
am.registerMediaButtonEventReceiver(RemoteControlReceiver);
...

// Stop listening for button presses
am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
</pre>

<p>Typically, apps should unregister most of their receivers whenever they become inactive or
invisible (such as during the {@link android.app.Activity#onStop onStop()} callback). However, it’s
not that simple for media playback apps&mdash;in fact, responding to media playback buttons is most
important when your application isn’t visible and therefore can’t be controlled by the on-screen
UI.</p>

<p>A better approach is to register and unregister the media button event receiver when your
application gains and losses the audio focus. This is covered in detail in the next lesson.</p>
+156 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading