Jeff Hines, Kindle Fire test team, and Chirag Mehta, a2z Developer Center Inc., an Amazon.com company, are our bloggers for this post.
This third post in our Top 10 App Optimizations for Kindle Fire series features actionable measures you can take when optimizing an app to correctly handle hibernation on Kindle Fire.
Your app must account for hibernation on Kindle Fire—whether the hibernation is user initiated or occurs after the screen times out. Similar to the Quick Settings optimization, hibernation optimization requires a proper handling of the onPause() and onResume() methods.
Not all apps react similarly when hibernated, as the expected behavior is dependent on the nature of the app. We have identified frequent hibernation issues and the solutions to correct them.
When initiated, hibernation on Kindle Fire acts as a battery saver after a screen timeout or when a user taps the device’s power button. During hibernation, any active network connections are disabled by default. To return from hibernation, users are presented with the lock screen and must slide to resume.
Upon hibernation, the expected behavior for most apps is to enter a paused state, using the onPause() method, and then to restore app state upon return by using the onResume() method. Of course, apps that are static in nature and rely on user interaction to change state can simply run in the background during hibernation.
In general, apps running in the background are expected to cease all background sound. However, some apps should continue to emit audio if this is their core functionality—such as music players or alarms.
As mentioned earlier, network connections are disabled by default during hibernation as an additional measure to save battery life on Kindle Fire. Upon leaving hibernation, any previously connected network connection will be restored.
If your app requires an always-on, active network connection, then you can ensure that users remain connected during hibernation by using the following sample code:
try {
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
final WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
final ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
final State wifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState();
// Log the current WiFi state.
Log.i(LOG_TAG, getString(R.string.lock_service_status_current_state) + " " + wifi.toString());
// Acquire the reference to the wake lock.
m_wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getString(R.string.lock_service_wake_lock_name));
// Ensure that the wake lock is reference counted.
m_wakeLock.setReferenceCounted(true);
// Acquire a wake lock to keep the CPU running.
if (!m_wakeLock.isHeld()) {
m_wakeLock.acquire();
}
// Acquire a WiFi lock to keep the WiFi radio awake.
m_wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL, getString(R.string.lock_service_wifi_lock_name));
// Ensure that the WiFi lock is reference counted.
m_wifiLock.setReferenceCounted(true);
if (!m_wifiLock.isHeld()) {
m_wifiLock.acquire();
}
// Perform the business logic.
performBusinessLogic();
} catch (final IOException e) {
Log.e(LOG_TAG, e.getMessage());
sendStatusMessage(e.getMessage());
} finally {
// Release the locks.
if (m_wakeLock != null && m_wakeLock.isHeld()) {
m_wakeLock.release();
}
if (m_wifiLock != null && m_wifiLock.isHeld()) {
m_wifiLock.release();
}
// Log the status.
final java.text.DateFormat dateFormat = DateFormat.getTimeFormat(this);
final Date date = new Date();
Log.i(LOG_TAG, getString(R.string.lock_service_status_release) + " " + dateFormat.format(date));
}
}
Apps that do not appropriately handle hibernation on Kindle Fire exhibit similar behavior to apps not optimized for Kindle Fire’s Quick Settings. When mishandling hibernation, apps may exhibit the following behavior:
Much like our previous entries in the series, correctly implementing the onPause() and onResume() methods are key to resolving any negative behavior in association with hibernation. When hibernation is enacted, the onPause() method will be called during your app’s current activity. When returning to your app after the power button is tapped and the lock screen is slid, the onResume() method is called. To ensure that your app returns to its previous state before hibernation occurred, your app should save state in the onPause() method and reload the state in the onResume() method.
If your app plays audio clips using the MediaPlayer object, be sure to call pause() within the onPause() method, and start() in the onResume() method in your app. This will ensure audio clips do not continue to play when the device hibernates.
For a technical perspective of the onPause() and onResume() methods, review our code segments included in part one of our Top 10 Optimizations for Kindle Fire series. To find more information about these and other methods, you may also find it helpful to visit: http://developer.android.com/reference/android/app/Activity.html
Check back for our next optimization post in which we will discuss ways to ensure your app installs successfully on Kindle Fire.