From 604e4ed4814169f85312a1ca788b81c819b9f049 Mon Sep 17 00:00:00 2001
From: Scott Main 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—only apps that hold the audio focus should play audio. Before your app starts playing audio it should request—and receive—the audio focus.
+Likewise, it should know how to listen for a loss of audio focus and respond appropriately when that
+happens. 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. 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). 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. 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. 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. Ducking is particularly suitable for apps that use the audio stream intermittently, such as for
+audible driving directions. 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. 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. 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—permanent loss, transient loss, and transient with ducking permitted. 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. 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—allowing the new audio player to exclusively handle
+those events—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. 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.
+
+ In the case of a transient loss of audio focus where ducking is permitted, rather than pausing
+playback, you can "duck" instead. 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. 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. 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. 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. How your app behaves might be affected by which hardware its output is being routed to. 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: 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. 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—while for games you may choose to significantly
+lower the volume. 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. 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. 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. 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. The first step to creating a predictable audio experience is understanding which audio stream
+your app will use. 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. 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. 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.
+
+ 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. 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.
+
+ 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—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.
+
+ 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. 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. 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. 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}. The following snippet shows how to extract the media button pressed and affects the media playback accordingly. 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. 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.
+
+ 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—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. 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. When you're altering the frequency of your background updates to reduce the effect of those
+updates on battery life, checking the current battery level and charging state is a good place to
+start. The battery-life impact of performing application updates depends on the battery level and
+charging state of the device. The impact of performing updates while the device is charging over AC
+is negligible, so in most cases you can maximize your refresh rate whenever the device is connected
+to a wall charger. Conversely, if the device is discharging, reducing your update rate helps
+prolong the battery life. Similarly, you can check the battery charge level, potentially reducing the frequency of—or
+even stopping—your updates when the battery charge is nearly exhausted. Start by determining the current charge status. The {@link android.os.BatteryManager}
+broadcasts all battery and charging details in a sticky {@link android.content.Intent} that includes
+the charging status. Because it's a sticky intent, you don't need to register a {@link
+android.content.BroadcastReceiver}—by simply calling {@code registerReceiver} passing in
+{@code null} as the receiver as shown in the next snippet, the current battery status intent is
+returned. You could pass in an actual {@link android.content.BroadcastReceiver} object here, but
+we'll be handling updates in a later section so it's not necessary. You can extract both the current charging status and, if the device is being charged, whether
+it's charging via USB or AC charger:
+
+ Typically you should maximize the rate of your background updates in the case where the device is
+connected to an AC charger, reduce the rate if the charge is over USB, and lower it
+further if the battery is discharging. The charging status can change as easily as a device can be plugged in, so it's important to
+monitor the charging state for changes and alter your refresh rate accordingly. The {@link android.os.BatteryManager} broadcasts an action whenever the device is connected or
+disconnected from power. It's important to to receive these events even while your app isn't
+running—particularly as these events should impact how often you start your app in order to
+initiate a background update—so you should register a {@link
+android.content.BroadcastReceiver} in your manifest to listen for both events by defining the
+{@link android.content.Intent#ACTION_POWER_CONNECTED} and {@link
+android.content.Intent#ACTION_POWER_DISCONNECTED} within an intent filter. Within the associated {@link android.content.BroadcastReceiver} implementation, you can extract
+the current charging state and method as described in the previous step. In some cases it's also useful to determine the current battery level. You may choose to reduce
+the rate of your background updates if the battery charge is below a certain level. You can find the current battery charge by extracting the current battery level and scale from
+the battery status intent as shown here: You can't easily continually monitor the battery state, but you don't need to. Generally speaking, the impact of constantly monitoring the battery level has a greater
+impact on the battery than your app's normal behavior, so it's good practice to only monitor
+significant changes in battery level—specifically when the device enters or exits a low
+battery state. The manifest snippet below is extracted from the intent filter element within a broadcast
+receiver. The receiver is triggered whenever the device battery becomes low or exits the low
+condition by listening for {@link android.content.Intent#ACTION_BATTERY_LOW} and {@link
+android.content.Intent#ACTION_BATTERY_OKAY}. It is generally good practice to disable all your background updates when the battery is
+critically low. It doesn't matter how fresh your data is if the phone turns itself off before you
+can make use of it. In many cases, the act of charging a device is coincident with putting it into a dock. The next
+lesson shows you how to determine the current dock state and monitor for changes in device
+docking. Some of the most common uses for repeating alarms and background services is to schedule regular
+updates of application data from Internet resources, cache data, or execute long running downloads.
+But if you aren't connected to the Internet, or the connection is too slow to complete your
+download, why both waking the device to schedule the update at all? You can use the {@link android.net.ConnectivityManager} to check that you're actually
+connected to the Internet, and if so, what type of connection is in place. There's no need to schedule an update based on an Internet resource if you aren't connected to
+the Internet. The following snippet shows how to use the {@link android.net.ConnectivityManager}
+to query the active network and determine if it has Internet connectivity. It's also possible to determine the type of Internet connection currently available. Device connectivity can be provided by mobile data, WiMAX, Wi-Fi, and ethernet connections. By
+querying the type of the active network, as shown below, you can alter your refresh rate based on
+the bandwidth available. Mobile data costs tend to be significantly higher than Wi-Fi, so in most cases, your app's update
+rate should be lower when on mobile connections. Similarly, downloads of significant size should be
+suspended until you have a Wi-Fi connection. Having disabled your updates, it's important that you listen for changes in connectivity in order
+to resume them once an Internet connection has been established. The {@link android.net.ConnectivityManager} broadcasts the {@link
+android.net.ConnectivityManager#CONNECTIVITY_ACTION} ({@code
+"android.net.conn.CONNECTIVITY_CHANGE"}) action whenever the connectivity details have changed. You
+can register a broadcast receiver in your manifest to listen for these changes and resume (or
+suspend) your background updates accordingly. Changes to a device's connectivity can be very frequent—this broadcast is triggered
+every time you move between mobile data and Wi-Fi. As a result, it's good practice to monitor
+this broadcast only when you've previously suspended updates or downloads in order to resume them.
+It's generally sufficient to simply check for Internet connectivity before beginning an update and,
+should there be none, suspend further updates until connectivity is restored. This technique requires toggling broadcast receivers you've declard in the manifest, which is
+described in the next lesson. Android devices can be docked into several different kinds of docks. These include car or home
+docks and digital versus analog docks. The dock-state is typically closely linked to the charging
+state as many docks provide power to docked devices. How the dock-state of the phone affects your update rate depends on your app. You may choose
+to increase the update frequency of a sports center app when it's in the desktop dock, or disable
+your updates completely if the device is car docked. Conversely, you may choose to maximize your
+updates while car docked if your background service is updating traffic conditions. The dock state is also broadcast as a sticky {@link android.content.Intent}, allowing you to
+query if the device is docked or not, and if so, in which kind of dock. The dock-state details are included as an extra in a sticky broadcast of the {@link
+android.content.Intent#ACTION_DOCK_EVENT} action. Because it's sticky, you don't need to register a
+{@link android.content.BroadcastReceiver}. You can simply call {@link
+android.content.Context#registerReceiver registerReceiver()} passing in {@code null} as the
+broadcast receiver as shown in the next snippet. You can extract the current docking status from the {@code EXTRA_DOCK_STATE} extra:
+
+ If a device is docked, it can be docked in any one of four different type of dock:
+Request the Audio Focus
+
+
+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.
+}
+
+
+
+// Abandon audio focus when playback complete
+am.abandonAudioFocus(afChangeListener);
+
+
+
+// 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.
+}
+
+
+Handle the Loss of Audio Focus
+
+
+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
+ }
+ }
+};
+
+
+Duck!
+
+
+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
+ }
+ }
+};
+
+
+Check What Hardware is Being Used
+
+
+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?
+}
+
+
+
+Handle Changes in the Audio Output Hardware
+
+
+private class NoisyAudioStreamReceiver extends BroadcastReceiver {
+ @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);
+}
+
diff --git a/docs/html/training/managing-audio/index.jd b/docs/html/training/managing-audio/index.jd
new file mode 100644
index 000000000000..c7df39be7354
--- /dev/null
+++ b/docs/html/training/managing-audio/index.jd
@@ -0,0 +1,62 @@
+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
+
+Dependencies and prerequisites
+
+
+
+You should also read
+
+
+
+Lessons
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/html/training/managing-audio/volume-playback.jd b/docs/html/training/managing-audio/volume-playback.jd
new file mode 100644
index 000000000000..7038ddfbd782
--- /dev/null
+++ b/docs/html/training/managing-audio/volume-playback.jd
@@ -0,0 +1,156 @@
+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
+
+
+This lesson teaches you to
+
+
+
+You should also read
+
+
+
+Identify Which Audio Stream to Use
+
+Use Hardware Volume Keys to Control Your App’s Audio Volume
+
+
+setVolumeControlStream(AudioManager.STREAM_MUSIC);
+
+
+
+Use Hardware Playback Control Keys to Control Your App’s Audio
+Playback
+
+
+<receiver android:name=".RemoteControlReceiver">
+ <intent-filter>
+ <action android:name="android.intent.action.MEDIA_BUTTON" />
+ </intent-filter>
+</receiver>
+
+
+
+public class RemoteControlReceiver extends BroadcastReceiver {
+ @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.
+ }
+ }
+ }
+}
+
+
+
+AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
+...
+
+// Start listening for button presses
+am.registerMediaButtonEventReceiver(RemoteControlReceiver);
+...
+
+// Stop listening for button presses
+am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
+
+
+This lesson teaches you to
+
+
+
+You should also read
+
+
+Determine the Current Charging State
+
+IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+Intent batteryStatus = context.registerReceiver(null, ifilter);
+
+// Are we charging / charged?
+int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
+boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
+ status == BatteryManager.BATTERY_STATUS_FULL;
+
+// How are we charging?
+int chargePlug = battery.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB;
+boolean acCharge = chargePlug == BATTERY_PLUGGED_AC;
+
+Monitor Changes in Charging State
+
+<receiver android:name=".PowerConnectionReceiver">
+ <intent-filter>
+ <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
+ <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
+ </intent-filter>
+</receiver>
+
+public class PowerConnectionReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
+ boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
+ status == BatteryManager.BATTERY_STATUS_FULL;
+
+ int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+ boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB;
+ boolean acCharge = chargePlug == BATTERY_PLUGGED_AC;
+ }
+}
+
+
+Determine the Current Battery Level
+
+int level = battery.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
+int scale = battery.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
+
+float batteryPct = level / (float)scale;
+
+
+Monitor Significant Changes in Battery Level
+
+<receiver android:name=".BatteryLevelReceiver">
+<intent-filter>
+ <action android:name="android.intent.action.ACTION_BATTERY_LOW"/>
+ <action android:name="android.intent.action.ACTION_BATTERY_OKAY"/>
+ </intent-filter>
+</receiver>
+
+This lesson teaches you to
+
+
+
+
+You should also read
+
+
+Determine if You Have an Internet Connection
+
+ConnectivityManager cm =
+ (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
+boolean isConnected = activeNetwork.isConnectedOrConnecting();
+
+
+Determine the Type of your Internet Connection
+
+boolean isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;
+
+Monitor for Changes in Connectivity
+
+<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
+
+This lesson teaches you to
+
+
+
+
+You should also read
+
+
+Determine the Current Docking State
+
+IntentFilter ifilter = new IntentFilter(Intent.ACTION_DOCK_EVENT);
+Intent dockStatus = context.registerReceiver(null, ifilter);
+
+int dockState = battery.getIntExtra(EXTRA_DOCK_STATE, -1);
+boolean isDocked = dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
+
+
+Determine the Current Dock Type
+
+
Note that the latter two options were only introduced to Android in API level 11, so it's good +practice to check for all three where you are only interested in the type of dock rather than it +being digital or analog specifically:
+ +boolean isCar = dockState == EXTRA_DOCK_STATE_CAR; +boolean isDesk = dockState == EXTRA_DOCK_STATE_DESK || + dockState == EXTRA_DOCK_STATE_LE_DESK || + dockState == EXTRA_DOCK_STATE_HE_DESK;+ + +
Whenever the the device is docked or undocked, the {@link +android.content.Intent#ACTION_DOCK_EVENT} action is broadcast. To monitor changes in the +device's dock-state, simply register a broadcast receiver in your application manifest as shown in +the snippet below:
+ +<action android:name="android.intent.action.ACTION_DOCK_EVENT"/>+ +
You can extract the dock type and state within the receiver implementation using the same +techniques described in the previous step.
diff --git a/docs/html/training/monitoring-device-state/index.jd b/docs/html/training/monitoring-device-state/index.jd new file mode 100644 index 000000000000..e92e1e8a3027 --- /dev/null +++ b/docs/html/training/monitoring-device-state/index.jd @@ -0,0 +1,63 @@ +page.title=Monitoring Device State to Optimize Battery Life + +trainingnavtop=true +startpage=true +next.title=Monitoring the Battery Level and Charging State +next.link=battery-monitoring.html + +@jd:body + +For your app to be a good citizen, it should seek to limit its impact on the battery life of its +host device. After this class you will be able to build apps that monitor modify their functionality +and behavior based on the state of the host device.
+ +By taking steps such as disabling background service updates when you lose connectivity, or +reducing the rate of such updates when the battery level is low, you can ensure that the impact of +your app on battery life is minimized, without compromising the user experience.
+ +The simplest way to monitor device state changes is to create a {@link +android.content.BroadcastReceiver} for each state you're monitoring and register each of them in +your application manifest. Then within each of these receivers you simply reschedule your recurring +alarms based on the current device state.
+ +A side-effect of this approach is that your app will wake the device each time any of these +receivers is triggered—potentially much more frequently than required.
+ +A better approach is to disable or enable the broadcast receivers at runtime. That way you can +use the receivers you declared in the manifest as passive alarms that are triggered by system events +only when necessary.
+ + +Use can use the {@link android.content.pm.PackageManager} to toggle the enabled state on any +component defined in the manifest, including whichever broadcast receivers you wish to enable or +disable as shown in the snippet below:
+ +ComponentName receiver = new ComponentName(context, myReceiver.class); + +PackageManager pm = context.getPackageManager(); + +pm.setComponentEnabledSetting(receiver, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP)+ +
Using this technique, if you determine that connectivity has been lost, you can disable all of +your receivers except the connectivity-change receiver. Conversely, once you are connected you can +stop listening for connectivity changes and simply check to see if you're online immediately before +performing an update and rescheduling a recurring update alarm.
+ +You can use the same technique to delay a download that requires higher bandwidth to complete. +Simply enable a broadcast receiver that listens for connectivity changes and initiates the +download only after you are connected to Wi-Fi.
-- cgit v1.2.3-59-g8ed1b