Thursday, 30 June 2011

The Angling Trust's Google Map Campaign

Cormorant Watch

The UK's Angling Trust, has launched a new web site for anglers to record sightings of cormorants, goosanders and mergansers throughout the UK. The new site uses Google Maps to record user sightings of the birds in the UK.

The birds are having a major affect on UK fish stocks and the aim of the map is to gather data to help persuade the UK government of the need for action to protect fisheries. The map has been launched to coincide with the start of the coarse fishing season on rivers.

Anglers can record sightings and activity of cormorants anywhere in the UK, directly onto the map. Users can also use the map to view details of each recorded cormorant sighting and watch the real picture of cormorant predation in UK waters build up week by week.

Wednesday, 29 June 2011

Google I/O Presentation


Now that things have settled down from last month’s Google I/O, we thought it would be a good time to highlight some of the technical talks given by the App Engine team. At this year’s I/O, we emphasized some of the big themes we’ve been focusing on this past year: availability and productionization of our platform, removing limits while maintaining performance at scale, and developing new APIs.

Availability and Productionization of our Platform

Since App Engine automatically handles all of the sharding and distribution of your application across datacenters, we thought it would be important to talk about the strategies we use to run and maintain our platform. These talks also give you an opportunity to meet some of the engineers who carry pagers so you don’t have to.
  • More 9s Please: Under the Covers of the High Replication Datastore - We were excited to announce the HR Datastore in January, since it provides a high level of availability, even during unplanned outages, and even if an entire datacenter goes offline. HRD uses the paxos algorithm to distribute data across multiple datacenters. Alfred Fuller and Matt Wilder talk about the high level distribution strategy used and how this helps keep your app serving.
  • Life in App Engine Production - Let’s face it - everyone has some great war stories about running live applications. And the stories of Google’s SRE team probably rank with the best of them. Michael Handler and Alan Green talk about what goes right and what can go wrong running in Production.

Removing Limits while maintaining performance at scale

How can you design your application so you can transition from serving 1 user to 1 million users with the minimum amount of work? How do you make sure your user experience stays consistent for those users?
  • App Engine Backends - At I/O this year we launched App Engine Backends, which allow you to write long running processes on App Engine. Crunch numbers, process data, and build large in-memory models! Justin Haugh and Greg Darke give an overview of this new feature and cover best practices.
  • Scaling App Engine Applications - We always get lots of question on what it means and how it works to scale an app using App Engine (hint: low latency is the key!). Guido van Rossum and Justin Haugh explain how instances work and cover best practices for scaling your application.

Developing New APIs

  • Full Text Search - It took 8 days after App Engine’s initial launch for this feature request to be filed - and now work on the Full Text Search API is nearing completion. Bo Majewski and Ged Ellis give a preview of the upcoming App Engine Full Text Search API.
  • App Engine MapReduce- So you just want to analyze 5TB of data? You’ll probably need MapReduce to do so! Mike Aizatsky talks about the progress being made on the App Engine MapReduce framework and how you can use it to generate reports for your data.
  • Large-scale Data Analysis using the App Engine Pipeline API - Once you’ve written one MapReduce, you’ll probably want to write more, and then you’ll need a way to manage your application’s analysis pipeline. In this talk, Brett Slatkin discusses a lightweight API for managing MapReduce workflows.
Our team always enjoys participating in Google I/O because our engineers get to share their vision and discuss their work with a large audience. If you are interested in what some of our customers had to say at I/O, check out the Google Enterprise Blog. Of course, with App Engine featured in 23 talks for Google I/O, we couldn’t cover them all here. See the complete session list for I/O and discover all the talks on App Engine and more!

Google Goggles learns Russian and gets a new view

Some of you may already be using the new optical character recognition (OCR) and translation of Russian in Google Goggles that we previewed at last week’s Inside Search event. Starting today, we’re pleased to introduce some additional new features, including a map view of your Search History and the ability to copy contact and text results to the clipboard. We’ve also changed the results interface to make it easier to view and navigate through your results.

Russian optical character recognition (OCR) and translation
Since Google Goggles first launched in 2009, it has been able to recognize and translate text in a number of different languages, as long as the language used Latin characters. With the launch of OCR for Russian, Goggles is now able to read Cyrillic characters. Goggles will recognize a picture of Russian text and allow you to translate the text into one of over 40 other languages. Russian OCR is also available for users of Google Goggles on the Google Search app for iOS. Очень полезно!
You can take a picture of Russian text and translate it into over 40 languages.
Map view of your search history
If you’ve enabled search history on Goggles, your history contains a list of all the images that you’ve searched for, as well as some information about where you performed the search if you chose to share your location with Google. Sometimes this can be a pretty long list, so we wanted to give you another way to sort and visualize your Goggles results.

We’ve added a map view, which shows your Goggles image search history on a map so you can quickly zoom and pan to find a query from a particular location.
Easily toggle between map view and list view with the button in the upper right.
Copy contact and text results to clipboard
Finally, imagine that you wanted to grab a URL or telephone number from a sign and email it to yourself. Now, Goggles gives you the option of copying the recognized text to your phone’s clipboard, allowing you to paste the test into a number of applications.

To try these new features download Google Goggles 1.5 from Android Market, or scan the QR code below with your phone.

Monday, 27 June 2011

Using the power of mapping to support South Sudan

The Google Map Maker team, along with the World Bank and UNITAR/UNOSAT, held a unique event at the World Bank Headquarters in Washington, D.C., and a satellite event in Nairobi at the same time. More than 70 members of the Sudanese diaspora, along with regional experts from the World Bank, Sudan Institute, Voices for Sudan, The Enough Project and other organizations gathered together to map what is expected to become the world’s newest country later this year: the Republic of South Sudan. UN Secretary-General Ban Ki-moon has asked the international community “to assist all Sudanese towards greater stability and development” during and beyond this period of transition.

South Sudan is a large but under-mapped region, and there are very few high-quality maps that display essential features like roads, hospitals and schools. Up-to-date maps are particularly important to humanitarian aid groups, as they help responders target their efforts and mobilize their resources of equipment, personnel and supplies. More generally, maps are an important foundation for the development of the infrastructure and economy of the country and region.

The Map Maker community—a wide-ranging group of volunteers that help build more comprehensive maps of the world using our online mapping tool, Google Map Maker—has been contributing to the mapping effort for Sudan since the referendum on January 9. To aid their work, we’ve published updated satellite imagery of the region, covering 125,000 square kilometers and 40 percent of the U.N.’s priority areas, to Google Earth and Maps.
The goal of last week’s event was to engage and train members of the Sudanese diaspora in the United States, and others who have lived and worked in the region, to use Google Map Maker so they could contribute their local knowledge of the region to the ongoing mapping effort, particularly in the area of social infrastructure. Our hope is that this event and others like it will help build a self-sufficient mapping community that will contribute their local expertise and remain engaged in Sudan over time.

We were inspired by the group’s enthusiasm. One attendee told us: “I used to live in this small village that before today did not exist on any maps that I know of...a place unknown to the world. Now I can show to my kids, my friends, my community, where I used to live and better tell the story of my people.”
The group worked together to make several hundred edits to the map of Sudan in four hours. As those edits are approved, they’ll appear live in Google Maps, available for all the world to see. But this wasn’t just a one-day undertaking—attendees will now return to their home communities armed with new tools and ready to teach their friends and family how to join the effort. We look forward to seeing the Southern Sudanese mapping community grow and flourish.

Sunday, 26 June 2011

Google Maps HTML5 Elevation

Vizzuality, the Spanish developers of some of the coolest Google Maps apps, has created a Google Map that allows you to view all the world's mountain ranges.

The map uses an HTML5 canvas overlay to visualise elevation data worldwide. The map includes a slider that allows you to adjust the elevation above sea level that is shown on the map.

If you set the slider to 0 metres then most of the world's land is shaded on the map. If you drag the slider up to 5400 meters then suddenly the Himalayas look very lonely.

Visual Raster

New in Google Summer of Code

This summer we are writing a series of posts featuring the new organizations participating in their first Google Summer of Code. This is our fourth installment where the organizations explain their project in more detail and discuss the tasks the students are working on this summer.
Elgg is an open source social networking project that began as an experimental thesis project in 2004. The technical goals for Elgg are to create a social engine that is accessible to end users but easily extensible for developers. Elgg’s participation in this year’s Google Summer of Code is an amazing chance for Elgg to get involved with the larger OSS community.
As a first year organization, we were humbled and surprised by both the quantity and the quality of applications we received. Narrowing it down was difficult, but in the end we picked three talented and eager students with ambitious ideas.
Francisco Hidalgo is implementing a method to allow user-generated content to be translated into multiple languages -- an important feature for sites with a large international user base.
Ravindra Nath Kakarla is working to streamline the Elgg user experience by Ajaxifying large parts of the application. This is a high profile project that Elgg users (and core developers) can’t wait to see.
Saket Saurabh will implement a standardized web services API and build an accompanying Java client. This API will allow alternative interaction with Elgg sites and provide developers even more flexibility in how they work with Elgg.
By Brett Profitt, Elgg Organization Administrator
OpenIntents is an open source project entirely focused on Android. Early-on, in 2008, we believed that more could be done to develop key concepts of the Android operating system and generate awareness. OpenIntents is one of the few open source projects actively targeting extension of the mobile operating system, and housing expert knowledge on it.
OpenIntents educates and empowers developers to use revolutionary new key features of Android, most notably the Intents mechanism that enables applications to reuse and interface with other applications. We provide a registry that brings developers together so they can make their applications compatible, and we act as a standardization body.
OpenIntents also aims to develop general functionality that is not in Android currently, but we feel should be, as well as to pioneer new ways of working. To illustrate or push forward the above we develop samples and free applications. Some of these applications have grown to be quite popular and we support them in the Market, like OI File Manager or OI Shopping List.
In 2011 OpenIntents was selected to mentor two projects in the Google Summer of Code. The first student, Elena, will enhance our SensorSimulator which is used by developers to debug applications that make use of the device sensors, and in particular, she will look into improving the device representation and handling. Our second student, Andras, will develop Historify, a new application that will become an open timeline module that 3rd party apps can post to. The timeline shows the interaction history between the user and contacts regardless of technology, like phone calls, messages, or social media.
By Peli Oi, OpenIntents Organization Administrator


SymPy is a full fledged computer algebra system written completely in pure Python. It presently has some very powerful features, like symbolic differentiation and integration, series, limits, symbolic matrices, solvers, simplification, polynomials, and quantum physics. SymPy can be used as a library, or executed like a calculator from a Python or IPython prompt using the isympy script.
The SymPy code is written to be easy to read and easily extensible. This and the fact that SymPy is written in Python has made it a very popular open source computer algebra system. The code for SymPy is all BSD licensed, so just about anyone can use SymPy in their code. Also, SymPy does not require any external dependencies to run (other than Python), which means that SymPy can be used in any environment that can run Python, such as Google AppEngine or any desktop computer.
SymPy has participated in Google Summer of Code since 2007 under umbrella organizations such as the Python Software Foundation, Portland State University and the Space Telescope Science Institute. This year for the first time we were accepted by Google as a mentoring organization. We were able to accept nine student projects. You can follow the student’s progress on their projects here.
We look forward to what should be our best year for SymPy development ever!

These are just a few of the 50 new organizations participating in Google Summer of Code this year. Please check back next Friday when we highlight 4 more new organizations. For a complete list of the 175 organizations participating in the Google Summer of Code please visit  program site.

Open App Revolution storms IBM Innovate

As a follow on to the efforts shown at the OpenSocial SOTU, we brought the Open App Revolution to IBM Innovate (The Rational Software Conference). Innovate is IBM Rational's annual conference for software and product delivery. It was held this year in Orlando, FL from June 5th through 9th. Matt Marum (IBM) was at Innovate this year demonstrating a cool social integration using Rational application lifecycle management tools within the Jazz Interoperability Center of the exhibit hall.
Matt demonstrated how a single embedded experience OpenSocial gadget could be created that would work with multiple Application Lifecycle Management (ALM) tools through the use of the Open Services for Lifecycle Collaboration (OSLC). OSLC is an open community for developing standards to make integrating lifecycle tools easier . In the demonstration, he showed how ActivityStream activities could be generated from ALM tools using social rules to sort out business relevant activity.
These activities are then posted to an activity stream which was displayed within an enterprise morning report OpenSocial application running on an iPad and iPhone. The mobile device user could then interact with the underlying ALM resources using an embedded experience without switching contexts away from their social application. Leveraging open standards, he demonstrated the end to end scenario working on Rational Team Concert and Rational ClearQuest. He was also showed the embedded experience working with Rational Quality Manager and Rational Requirements Composer.
Even better, by using OpenSocial gadgets it all ran within a Jazz Dashboard and potentially any other OpenSocial container. Here is a preview video put together just before Innovate. Products shown are Rational Team Concert, Rational Quality Manager, Rational Requirements Composer, and Rational ClearQuest.
The demonstration was a big success! Attendees were excited by the opportunities of the social integration to change how they and their users work every day. This work is still at the "proof of concept" stage. However, you can track the progress of the work and get involved by following the OpenSocial spec list and Apache Shindig code base.

Saturday, 25 June 2011

Dive Into Location

I'm a big fan of location-based apps, but not their seemingly-inevitable startup latency.
Whether it's finding a place to eat or searching for the nearest Boris Bike, I find the delay while waiting for the GPS to get a fix, and then for the results list to populate, to be interminable. Once I’m in a venue and ready to get some tips, check-in, or review the food, I’m frequently thwarted by a lack of data connection.
Rather than shaking my fist at the sky, I’ve written an open-source reference app that incorporates all of the tips, tricks, and cheats I know to reduce the time between opening an app and seeing an up-to-date list of nearby venues - as well as providing a reasonable level of offline support — all while keeping the impact on battery life to a minimum.

Show Me the Code

You can check-out the Android Protips for Location open source project from Google Code. Don’t forget to read the Readme.txt for the steps required to make it compile and run successfully.

What Does it Actually Do?

It uses the Google Places API to implement the core functionality of apps that use location to provide a list of nearby points of interest, drill down into their details, and then check-in/rate/review them.
The code implements many of the best-practices I detailed in my Google I/O 2011 session,Android Protips: Advanced Topics for Expert Android Developers (video), including using Intents to receive location updates, using the Passive Location Provider, using and monitoring device state to vary refresh rates, toggling your manifest Receivers at runtime, and using the Cursor Loader.
The app targets Honeycomb but supports Android platforms from 1.6 and up.
Nothing would make me happier than for you to cut/copy/borrow / steal this code to build better location-based apps. If you do, I’d love it if you told me about it!

Now that you’ve got the code, let’s take a closer look at it

My top priority was freshness: Minimize the latency between opening the app and being able to check in to a desired location, while still minimizing the impact of the app on battery life.
Related requirements:
  • The current location has to be found as quickly as possible.
  • The list of venues should update when the location changes.
  • The list of nearby locations and their details must be available when we’re offline.
  • Check-ins must be possible while we’re offline.
  • Location data and other user data must be handled properly (see our prior blog post on best practices).

Freshness means never having to wait

You can significantly reduce the latency for getting your first location fix by retrieving the last known location from the Location Manager each time the app is resumed.
In this snippet taken from the GingerbreadLastLocationFinder, we iterate through each location provider on the device — including those that aren't currently available — to find the most timely and accurate last known location.
List<String> matchingProviders = locationManager.getAllProviders();
for (String provider: matchingProviders) {
  Location location = locationManager.getLastKnownLocation(provider);
  if (location != null) {
    float accuracy = location.getAccuracy();
    long time = location.getTime();
    if ((time > minTime && accuracy < bestAccuracy)) {
      bestResult = location;
      bestAccuracy = accuracy;
      bestTime = time;
    else if (time < minTime && 
             bestAccuracy == Float.MAX_VALUE && time > bestTime){
      bestResult = location;
      bestTime = time;
If there is one or more locations available from within the allowed latency, we return the most accurate one. If not, we simply return the most recent result.
In the latter case (where it’s determined that the last location update isn't recent enough) this newest result is still returned, but we also request a single location update using that fastest location provider available.
if (locationListener != null &&
   (bestTime < maxTime || bestAccuracy > maxDistance)) { 
  IntentFilter locIntentFilter = new IntentFilter(SINGLE_LOCATION_UPDATE_ACTION);
  context.registerReceiver(singleUpdateReceiver, locIntentFilter);      
  locationManager.requestSingleUpdate(criteria, singleUpatePI);
Unfortunately we can’t specify “fastest” when using Criteria to choose a location provider, but in practice we know that coarser providers — particularly the network location provider — tend to return results faster than the more accurate options. In this case I’ve requested coarse accuracy and low power in order to select the Network Provider when it’s available.
Note also that this code snippet shows the GingerbreadLastLocationFinder which uses the requestSingleUpdate method to receive a one-shot location update. This wasn’t available prior to Gingerbread - check out the LegacyLastLocationFinder to see how I have implemented the same functionality for devices running earlier platform versions.
The singleUpdateReceiver passes the received update back to the calling class through a registered Location Listener.
protected BroadcastReceiver singleUpdateReceiver = new BroadcastReceiver() {
  public void onReceive(Context context, Intent intent) {
    String key = LocationManager.KEY_LOCATION_CHANGED;
    Location location = (Location)intent.getExtras().get(key);
    if (locationListener != null && location != null)

Use Intents to receive location updates

Having obtained the most accurate/timely estimate of our current location, we also want to receive location updates.
The PlacesConstants class includes a number of values that determine the frequency of location updates (and the associated server polling). Tweak them to ensure that updates occur exactly as often as required.
// The default search radius when searching for places nearby.
public static int DEFAULT_RADIUS = 150;
// The maximum distance the user should travel between location updates. 
public static int MAX_DISTANCE = DEFAULT_RADIUS/2;
// The maximum time that should pass before the user gets a location update.
public static long MAX_TIME = AlarmManager.INTERVAL_FIFTEEN_MINUTES; 
The next step is to request the location updates from the Location Manager. In this snippet taken from the GingerbreadLocationUpdateRequester we can pass the Criteria used to determine which Location Provider to request updates from directly into the requestLocationUpdates call.
public void requestLocationUpdates(long minTime, long minDistance, 
  Criteria criteria, PendingIntent pendingIntent) {

  locationManager.requestLocationUpdates(minTime, minDistance, 
    criteria, pendingIntent);
Note that we're passing in a Pending Intent rather than a Location Listener.
Intent activeIntent = new Intent(this, LocationChangedReceiver.class);
locationListenerPendingIntent = 
  PendingIntent.getBroadcast(this, 0, activeIntent, PendingIntent.FLAG_UPDATE_CURRENT);
I generally prefer this over using Location Listeners as it offers the flexibility of registering receivers in multiple Activities or Services, or directly in the manifest.
In this app, a new location means an updated list of nearby venues. This happens via a Service that makes a server query and updates the Content Provider that populates the place list.
Because the location change isn’t directly updating the UI, it makes sense to create and register the associated LocationChangedReceiver in the manifest rather than the main Activity.
<receiver android:name=".receivers.LocationChangedReceiver"/>
The Location Changed Receiver extracts the location from each update and starts the PlaceUpdateService to refresh the database of nearby locations.
if (intent.hasExtra(locationKey)) {
  Location location = (Location)intent.getExtras().get(locationKey);
  Log.d(TAG, "Actively Updating place list");
  Intent updateServiceIntent = 
    new Intent(context, PlacesConstants.SUPPORTS_ECLAIR ? EclairPlacesUpdateService.class : PlacesUpdateService.class);
  updateServiceIntent.putExtra(PlacesConstants.EXTRA_KEY_LOCATION, location);
  updateServiceIntent.putExtra(PlacesConstants.EXTRA_KEY_RADIUS, PlacesConstants.DEFAULT_RADIUS);
  updateServiceIntent.putExtra(PlacesConstants.EXTRA_KEY_FORCEREFRESH, true);


Monitor inactive providers for a better option

The snippet from PlacesActivity below shows how to monitor two important conditions:
  • The Location Provider we are using being deactivated.
  • A better Location Provider becoming available.
In either case, we simply re-run the process used to determine the best available provider and request location updates.
// Register a receiver that listens for when the provider I'm using has been disabled. 
IntentFilter intentFilter = new IntentFilter(PlacesConstants.ACTIVE_LOCATION_UPDATE_PROVIDER_DISABLED);
registerReceiver(locProviderDisabledReceiver, intentFilter);
// Listen for a better provider becoming available.
String bestProvider = locationManager.getBestProvider(criteria, false);
String bestAvailableProvider = locationManager.getBestProvider(criteria, true);
if (bestProvider != null && !bestProvider.equals(bestAvailableProvider))
  locationManager.requestLocationUpdates(bestProvider, 0, 0, 
    bestInactiveLocationProviderListener, getMainLooper());

Freshness means always being up to date. What if we could reduce startup latency to zero?

You can start the PlacesUpdateService in the background to refresh the list of nearby locations while your app is in the background. Done correctly, a relevant list of venues can be immediately available when you open the app.
Done poorly, your users will never find this out as you’ll have drained their battery too quickly.
Requesting location updates (particularly using the GPS) while your app isn’t in the foreground is poor practice, as it can significantly impact battery life. Instead, you can use the Passive Location Provider to receive location updates alongside other apps that have already requested them.
This extract from the FroyoLocationUpdateRequester enables passive updates on Froyo+ platforms.
public void requestPassiveLocationUpdates(long minTime, long minDistance, PendingIntent pendingIntent) {
    PlacesConstants.MAX_TIME, PlacesConstants.MAX_DISTANCE, pendingIntent);    }
As a result receiving background location updates is effectively free! Unfortunately the battery cost of your server downloads aren’t, so you’ll still need to carefully balance how often you act on passive location updates with battery life.
You can achieve a similar effect in pre-Froyo devices using inexact repeating non-wake alarms as shown in the LegacyLocationUpdateRequester.
public void requestPassiveLocationUpdates(long minTime, long minDistance, 
  PendingIntent pendingIntent) {

    PlacesConstants.MAX_TIME, pendingIntent);    }
Rather than receiving updates from the Location Manager, this technique manually checks the last known location at a frequency determined by the maximum location update latency.
This legacy technique is significantly less efficient, so you may choose to simply disable background updates on pre-Froyo devices.
We handle updates themselves within the PassiveLocationChangedReceiver which determines the current location and starts the PlaceUpdateService.
if (location != null) {
  Intent updateServiceIntent = 
    new Intent(context, PlacesConstants.SUPPORTS_ECLAIR ? EclairPlacesUpdateService.class : PlacesUpdateService.class);
  updateServiceIntent.putExtra(PlacesConstants.EXTRA_KEY_LOCATION, location);
  updateServiceIntent.putExtra(PlacesConstants.EXTRA_KEY_FORCEREFRESH, false);
  context.startService(updateServiceIntent);   }

Using Intents to passively receive location updates when your app isn't active

You’ll note that we registered the Passive Location Changed Receiver in the application manifest.
<receiver android:name=".receivers.PassiveLocationChangedReceiver"/>
As a result we can continue to receive these background updates even when the application has been killed by the system to free resources.
This offers the significant advantage of allowing the system to reclaim the resources used by your app, while still retaining the advantages of a zero latency startup.
If your app recognizes the concept of “exiting” (typically when the user clicks the back button on your home screen), it’s good form to turn off passive location updates - including disabling your passive manifest Receiver.

Being fresh means working offline

To add offline support we start by caching all our lookup results to the PlacesContentProvider and PlaceDetailsContentProvider.
Under certain circumstances we will also pre-fetch location details. This snippet from the PlacesUpdateService shows how pre-fetching is enabled for a limited number of locations.
Note that pre-fetching is also potentially disabled while on mobile data networks or when the battery is low.
if ((prefetchCount < PlacesConstants.PREFETCH_LIMIT) &&
    (!PlacesConstants.PREFETCH_ON_WIFI_ONLY || !mobileData) &&
    (!PlacesConstants.DISABLE_PREFETCH_ON_LOW_BATTERY || !lowBattery)) {
  // Start the PlaceDetailsUpdateService to prefetch the details for this place.
We use a similar technique to provide support for offline checkins. The PlaceCheckinService queues failed checkins, and checkins attempted while offline, to be retried (in order) when the ConnectivityChangedReceiver determines that we’re back online.

Optimizing battery life: Smart Services and using device state to toggle your manifest Receivers

There's no point running update services when we aren’t online, so the PlaceUpdateService checks for connectivity before attempting an update.
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null &&
If we’re not connected, the Passive and Active Location Changed Receivers are disabled and the the ConnectivityChangedReceiver is turned on.
ComponentName connectivityReceiver = 
  new ComponentName(this, ConnectivityChangedReceiver.class);
ComponentName locationReceiver = 
  new ComponentName(this, LocationChangedReceiver.class);
ComponentName passiveLocationReceiver = 
  new ComponentName(this, PassiveLocationChangedReceiver.class);

The ConnectivityChangedReceiver listens for connectivity changes. When a new connection is made, it simply disables itself and re-enables the location listeners.

Monitoring battery state to reduce functionality and save power

When your phone is on its last 15%, most apps are firmly in the back seat to conserving what watts you have remaining. We can register manifest Receivers to be alerted when the device enters or leaves the low battery state.
<receiver android:name=".receivers.PowerStateChangedReceiver">
    <action android:name="android.intent.action.ACTION_BATTERY_LOW"/>
    <action android:name="android.intent.action.ACTION_BATTERY_OKAY"/>
This snippet from the PowerStateChangedReceiver disables the PassiveLocationChangedReceiver whenever the device enters a low battery state, and turns it back on once the battery level is okay.
boolean batteryLow = intent.getAction().equals(Intent.ACTION_BATTERY_LOW);
  batteryLow ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED :
You can extend this logic to disable all prefetching or reduce the frequency of your updates during low battery conditions.

Share This Post