Converting a Bookmarklet into an Android Share app

Partial screenshot of the Delicious web pageI read quite a lot of web pages on my Android tablet and it is useful to be able to save them to my Delicious account so that I can look at them again later. On desktop browsers it is possible to save items using a small bookmarklet that lives on a menu bar in the browser. This very handily gets the title and address of the current page and prepopulates the fields on the Delicious save form, it also shows suggested tags. Sadly on the tablet it is not possible to use bookmarklets* in the same way and the apps I found that shared to Delicious used the mobile version of the save page. So I went about converting the bookmarklet into a small app that would hook into Android's Share functionality. The app could easily be repurposed to use in the place of other bookmarklets too, so here is an explanation of how it works.

To start with let's have a look at the JavaScript code used by the Delicious bookmarklet:
javascript:(function(){location.href='http://www.delicious.com/save?url='+encodeURIComponent(window.location.href)+'&title='+encodeURIComponent(document.title)+'&notes='+encodeURIComponent(''+(window.getSelection?window.getSelection():document.getSelection?document.getSelection():document.selection.createRange().text))+'&v=6&jump=yes'})()

It looks complex, but when you look at it closely it is possible to see that what it is doing is building a URL for the Delicious save page, reading in the current page's title and URL as parameters and redirecting the browser. It also uses the current text selection as the text for the note, but after experimenting I left out this functionality from the app as it didn't really fit in with the Android experience (it is just as easy to copy and paste sections of text anyway). If you were to click on the bookmarklet while viewing this blog the code above would run and your browser would be redirected to this URL:

http://www.delicious.com/save?url=http%3A%2F%2Fwww.greenhughes.com%2F&title=greenhughes.com%20|%20Life%20is%20too%20short%20for%20bad%20technology&notes=&v=6&jump=yes

Now we have determined what the bookmarklet does, how do we go about getting an Android tablet to do something similar? When you view a page in the browser on an Android device you also get access to a Share menu. This allows you to send the link to a variety of services such as Email, Facebook and so on. At a system level the way that this is implemented is through a system called Intents and Intent Filters. The idea here is that when you want to do something, instead of calling a program directly you tell the system what you want to do and then it goes and finds programs that are capable of performing that action. Think of this as the different between the statements "Hey I want to open Chrome and look at the web page" and "I want to look at this web page, find me a program that can do that". If more than one program can perform that action the user may have to chose between them.

The intent we are interesting in is called ACTION_SEND. This is fired whenever the user presses the share button, so in our app we must register an interest in this intent so that we can react to it. This is done by adding the following lines to the activity entry in the AndroidManifest.xml file.

<intent-filter>
  <action android:name="android.intent.action.SEND" />
  <category android:name="android.intent.category.DEFAULT" />
  <data android:mimeType="text/plain" />
</intent-filter>

Inside the onCreate() method in our app we need to work out if the app is running because the user tapped on the icon directly in the apps menu or because the share button was pressed. So we need to find out information about the call to our app. Start with these lines:

// Get information about the call to start this activity
Intent intent = getIntent();
Bundle extras = intent.getExtras();
String action = intent.getAction();

Now we can decide what to do in each case, an If block does the trick:

if (action.equals(Intent.ACTION_SEND)) {
   // The share function was used
}
else {
   // a normal launch
}

In the extras Bundle the ACTION_SEND call also gives us some other information. We get properties for the URL of the page, the title of the page (depending on the program hosting the share button), the favicon and a screenshot of the web page. For this case we want the URL which is provided by the android.intent.extra.TEXT extra and the page title which is provided by the android.intent.extra.SUBJECT extra (if available). These can be read into strings using the code below:

String pageUrl = extras.getString("android.intent.extra.TEXT");
String pageTitle = extras.getString("android.intent.extra.SUBJECT");
// Some apps do not provide the page title, so in this case use the URL again
if (pageTitle == null) {
  pageTitle = pageUrl;
}

With this information determined, we can start to build the URL for the Delicous web page. This is done with the code below:

// Start to build the Delicious URL
Uri.Builder deliciousSaveUrl = Uri.parse("http://www.delicious.com").buildUpon();
deliciousSaveUrl.appendPath("save");
// Add the parameters from the call
deliciousSaveUrl.appendQueryParameter("url", pageUrl);
deliciousSaveUrl.appendQueryParameter("title", pageTitle);
deliciousSaveUrl.appendQueryParameter("notes", "");
deliciousSaveUrl.appendQueryParameter("v", "6");
deliciousSaveUrl.appendQueryParameter("jump", "yes");

Notice how the query parameters are added, the Uri.Builder class does the work of encoding for us. With the URL constructed we can build an Intent to display the new web page. Notice the code below also has a line to enable the user to pick the browser they want to use if they have more than one installed.

// Load the constructed URL in the browser
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(deliciousSaveUrl.build());
// If user has more then one browser installed give them a chance to
// select which one they want to use
startActivity(Intent.createChooser(i, getString(R.string.which_browser)));

The app's work is now done, so a call to this.finish(); can be made to close the app down. That is the core of how the app works, the rest of the code is to display a screen with some instructions on if the app is launched directly. Hopefully you can see here that the functionality of a bookmarklet can be added to Android, the approach is slightly different and it takes a little bit of coding but the end result fits in well with the system. You can see the finished result in the “Tablet to Delicious” app available from the Android market. The icon was created using the wonderful Android Asset Studio. I am sure there are lots of ways the code could be improved (as I am still learning about Android!) and converted for other purposes so I have made the source code available on Google code at: http://code.google.com/p/tablettodelicious/.

* Update: Martin Hawksey has written up a workaround on how to use Bookmarklets from within the browser by synchronising it onto the device and making it available on the Bookmarks tab. You can find his method here: http://mhawksey.tumblr.com/post/7318404662/how-to-use-bookmarklets-on-an-android-tablet. There are advantages and disadvantages to both methods of course, his method will enable you to use the bookmarklet more quickly, whereas converting it into an app will enable you to use the functionality in any app with a share option (e.g. the Market, newsreaders). So have a look and pick the best option for you..

Comments

I am very interested in this subject, but new to android and don't know javascript.

Reading the above and other sites, it looks like it should be possible to do the above with a GPS bookmarklet that generates GPX waypoint route files from google maps directions. (see http://bevhoward.com/G2WPT.htm)

The bookmarklet described on that page generates and routes the user from google maps to a new page with a form containing editable GPX code, which can then be edited and saved as a GPS navigation file.

I have tried the steps at http://www.hyperborea.org/journal/2012/08/bookmarklets-chrome-android/
but that doesn't work... probably because of the fact that android does not support java.

Any ideas, suggestions or pointers to other links?

Thanks in advance,
Beverly Howard

Add new comment

Comments are always very welcome, but please note the following:
  • Sadly due to the high number of spam comments recently all comments are now manually moderated. You comment will therefore not appear on the site instantly.
  • Comments on this web site are monitored for spam using Mollom. By posting a comment, you accept that your message and other personal details about you will be analysed and stored for anti-spam and quality monitoring purposes, in accordance with Mollom's privacy policy.
  • Please use your own name not a company or website name to submit comments. Your comment will be removed if you don't do this.
  • All links in comments will be marked with a no follow attribute. That means posting a link to your site here won't help your search engine rankings.
  • By submitting a comment you agree that your comment can be reproduced under the same licensing terms as the rest of the content on the site.
  • Comments can be removed at any time without explanation, but won't be removed just because you disagreed with something I said.