INVISIBLE HEADING 1

How Does Google Plus Instant Upload Work?

August 18, 2011 5:13 pm by
Instant Upload

Introduction

When I first heard about Google Plus and their Instant Upload feature, my initial thought was “how does this work?”.  I did a quick search on Google to see if there were any other people who were curious about how they do it.  I found only one useful result, this stack overflow post (stack overflow has been invaluable this summer), and it got me thinking about how cool it would be to try to do the same thing.  The words ContentProvider and ContentObserver was gibberish to me but I dedicated one night to see if I can figure this thing out.  Turned out, it was actually quite easy and not that hard to understand.

This is probably not the exact way that Google+ used to implement Instant Uploads, but it provides the same functionality, with a bonus that Google+ does not have – that it’ll work with any camera app, not just the native camera app.  My hope is that this tutorial will help others that may be curious about how to do something similar.

Content Providers are the only way to share data across different applications.  They can store and read data, and Android has a bunch of content providers already provided for you for common data types, such as video, audio, images and contacts.

Content Observers are just that.  It’s an abstract class that has a method that gets called when it observes a change in a content provider.

Hopefully you figured out now that what we simply have to do is register a content observer to the images content provider.

InstantUploadActivity

Let’s create a simple and useless Android project that will detect when a picture is taken and display the most recent picture’s file name in a TextView.  The content provider that we want to observe is the one that Android provides for images, and the URI for that is MediaStore.Images.Media.EXTERNAL_CONTENT_URI.

We start with the onCreate method in the Activity:

public class InstantuploadActivity extends Activity {

    private PhotosObserver instUploadObserver = new PhotosObserver();
    private String saved;
    private TextView tv;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        tv = (TextView)findViewById(R.id.textview);

        this.getApplicationContext()
            .getContentResolver()
            .registerContentObserver(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false,
                instUploadObserver);
        Log.d("INSTANT", "registered content observer");
}

Upon creation of this Activity, we register our custom PhotosObserver (which extends ContentObserver) to the images content provider.

Recall that the goal for this project is to simply take the most recent picture’s file name and display it in our Activity’s TextView, tv.  To get alerted when a new picture is taken, we have to create a class that extends ContentObserver and implement the onChange method:

private class PhotosObserver extends ContentObserver {

    public PhotosObserver() {
        super(null);
    }

    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        Media media = readFromMediaStore(getApplicationContext(),
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        saved = "I detected " + media.file.getName();
        Log.d("INSTANT", "detected picture");
    }
}

private Media readFromMediaStore(Context context, Uri uri) {
    Cursor cursor = context.getContentResolver().query(uri, null, null,
        null, "date_added DESC");
    Media media = null;
    if (cursor.moveToNext()) {
        int dataColumn = cursor.getColumnIndexOrThrow(MediaColumns.DATA);
        String filePath = cursor.getString(dataColumn);
        int mimeTypeColumn = cursor
            .getColumnIndexOrThrow(MediaColumns.MIME_TYPE);
        String mimeType = cursor.getString(mimeTypeColumn);
        media = new Media(new File(filePath), mimeType);
    }
    cursor.close();
    return media;
}

private class Media {
    private File file;
    @SuppressWarnings("unused")
    private String type;

    public Media(File file, String type) {
        this.file = file;
        this.type = type;
    }

    public String getType() {
        return type;
    }

    public File getFile() {
        return file;
    }
}

In the onChange method we call readFromMediaStore, which will retrieve data about the most recent picture (the one that was just taken). readFromMediaStore initializes a Cursor on the same Images URI that we’ve been observing.  We then grab the filepath and the filetype from the first result (note: the cursor was sorted by “date_added DESC”) and create a new Media to return.  Keep in mind that this can be done when our Activity is not running in the foreground.  You can launch InstantUploadActivity, press “Home” to back out, then go to Camera and take a picture – and the onChange method will still get called.

From here, we simply set the String variable saved to display the filename such that when you go back to the Activity, the filename of the picture you have just taken is displayed in the TextView via the onResume method:

@Override
public void onResume() {
    super.onResume();
    if (saved != null) {
        tv.setText(saved);
    }
}

Lastly, don’t forget to unregister the content observer if onDestroy is called:

@Override
public void onDestroy() {
    super.onDestroy();
    this.getApplicationContext().getContentResolver()
            .unregisterContentObserver(instUploadObserver);
    Log.d("INSTANT", "unregistered content observer");
}

You can do much better than just setting text on a TextView.  You can take that image and resize it, and then upload it somewhere, or you can automatically apply an image filter on each picture or do both!  There are many cool things you can do with this.

Check out the full source code on github here.

Conclusion

This was my second hackathon project at Facebook, and I was able to implement this functionality into the Android Facebook app successfully such that whenever you took a picture from any camera app, it would get uploaded to your Mobile Uploads album.  Instead of storing the filepath of the most recent picture like in the example above, I grabbed the URI of the picture that was just taken and sent it to an upload service in the Facebook app that took care of uploading the picture to your album.  I also built some preferences so that you can enable or disable it depending on if you’re connected to wifi, roaming, or charging your phone.

Unfortunately, my hackathon project is not going to be implemented but it was a fun learning experience.  It is also hard to describe the utter excitement when seeing this work for the first time at 5am, having a picture taken from your camera and onto Facebook in a matter of seconds.  Stay tuned for another tutorial on another hackathon project!

EDIT: And here it is: How to NFC on Android

Tags: , , , , , , ,

About

Jesse is a software engineer at Facebook, who just graduated from UC Berkeley. Passionate about mobile technology and entrepreneurship, he started his own blog as a home for his tutorials, projects, and random thoughts. Follow him on Facebook to stay updated on his latest tutorials and projects.

10 Comments »

  1. dude awesome post, will try this later.

    Comment by Dmitry Kislyuk — August 18, 2011 @ 5:29 PM

  2. whoa whoa whoa curiousity satisfied

    Comment by Nelson Hoang — August 20, 2011 @ 1:09 AM

  3. Nice article. The hackathon you did for Facebook is exactly the idea that led me to your post. I found another app doing this via a Service, since the broadcast action for android.intent.action.CAMERA_BUTTON isn’t always implemented by device manufacturers (so say some people).

    Thanks for the info!

    Comment by Todd — November 28, 2011 @ 7:44 PM

  4. Very nice post.
    Can you post, QR/BAR code reader app? It would be great help for many people looking for it.Because nobody is explaining about QR/BAR code reader the way you post.
    Thanks in advance.

    Comment by Geet — March 29, 2012 @ 2:43 AM

  5. Why not just use a CursorLoader instead? Either way, queries to the MediaStore should be performed on a separate worker thread.

    Comment by Alex Lockwood — August 20, 2012 @ 5:01 PM

  6. hello,
    how can we upload an image on google plus application through android
    please give me methods or sample code
    thank you

    regards
    nitin gupta

    Comment by nitin gupta — August 24, 2012 @ 2:55 AM

  7. how can we upload an image on google plus through android code
    please give me sample code ..
    thanks
    regards
    nitin gupta

    Comment by nitin gupta — August 24, 2012 @ 2:58 AM

  8. [...] Thanks to Femi’s answer in this post, I was able to take what he said and figure out how to emulate Google+’s Instant Upload feature. I wrote a tutorial about it here:http://www.jessechen.net/blog/how-does-google-plus-instant-upload-work/………………………………… [...]

    Pingback by Android — How does Google+ instant upload work? | Android Development tutorial | Android Development tutorial — September 1, 2012 @ 8:43 PM

  9. Everyone loves it when people come together and share views.
    Great blog, continue the good work!

    Comment by refencement google — December 25, 2012 @ 7:27 AM

  10. If some one wishes expert view regarding blogging and site-building then i suggest him/her to pay
    a visit this webpage, Keep up the pleasant job.

    Comment by cold cal — February 17, 2013 @ 1:09 PM

RSS feed for comments on this post. TrackBack URL

Leave a comment