Blog | jessechen.net

How Does Google Plus Instant Upload Work?

August 18, 2011 5:13 pm by

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

Filed under: Android,How to — Tags: , , , , , , , — Jesse Chen @ 5:13 PM

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.


College So Far

September 30, 2010 4:03 pm by

My name is Jesse Chen, and I am a third year student here at UC Berkeley studying Electrical Engineering and Computer Sciences.

Sometimes, I have to say that in my head repeatedly to convince myself of my existence in this world.  As one of the many hundreds of students studying EECS here at UC Berkeley, it makes me think about where each and every one of us will be.  Truthfully, I feel like there is very little that separates a person from another.  As an EECS major, there are probably true generalizations that one can make.  For example: probably Asian, below average hygiene, spends majority of life staring at a LCD screen, enjoys working with computers and likes video games.  Right?  These generalizations bunch us into a single group, and it is very hard to stick out and be someone unique and different.  I feel like that is one of my challenges here while I’m in college, which is to try to find who I really am.  But not only that, I want to be different from my peers, I’m not going to be another cookie-cutter EECS major who just came fresh out of the UC Berkeley oven.

There are much more talented students out there in EECS than me, it is undeniable and I am happy to be at a university that promotes intellectual curiosity and academic success than a university that doesn’t.  It inspires me to do better as well, but at the same time, sometimes you get that sunken feeling that no matter how hard you try, you just can’t be as good as some people.  As if their intelligence is a natural trait that you somehow did not receive when you were born and there is no way to reach the same level as some of your peers.  To this day, I still think about it – if this natural tendency for someone to do better academically than another is a hard-coded trait that can’t be changed, or if it is because their priorities are different from yours.  I can say that with me balancing school, work, long-distance girlfriend, basketball/video games at the same time is a respectable challenge.  However, against someone who does not have as much priorities, perhaps they do better at school because they do not have as much things to worry about?  Maybe it is because they are more productive with their time.

As a third year, I am among the ranks of my peers who are seeking for internships this summer to gain work experience and for the possibility of joining a company right after graduation.  Job recruiters are going to be looking among hundreds of candidates, people who are just like me.  Who will they select for the next round of interviews and who to eliminate?  Each of us are all trying to separate themselves from the stereotypical model of an UC Berkeley EECS student, trying to be unique and different to look more appealing.   My questions, to myself, are: How are you different from the other people trying to get the same internships?  What makes you any better than the other candidates?  Why should they hire you?

Time to think real hard about that – internship seeking time is now.

Filed under: General — Tags: , , , , — Jesse Chen @ 4:03 PM

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.