Interacting with Google Tasks on Android

Since I’ve been playing with Google Tasks, I wanted to look at my task from my Android phone. Sadly, all the application I could find were using a lot more permissions than I like to give. Therefore, I decided to look into why all these permissions are needed. This will be a little tutorial on interacting with Google Tasks on Android.

Disclaimer: I have not yet published an application using this, so it is possible that something is missing. I will update this post as soon as I have more information (or remove this disclaimer if nothing more is needed).

Project Setup

There are two basic files that need modification in order to be able to use Google Tasks on Android.

The first files you need to modify is the AndroidManifest.xml file. You will need to add the android.permission.INTERNET by adding the following line:

This permission is used to allow your application to connect to the Internet.

The second file that needs modification is the app/build.gradle file. Adding the following lines to this file will add the needed libraries to your project’s dependencies:

Do note that I had to force the version of com.google.code.findbugs:jsr305 in order to fix a dependency issue.

Google API Setup

Configuring the Google Backend services for Android is a little bit different from doing so for desktop applications. I already did a quick tutorial on doing the configuration for Android here.

Handling the user’s credentials

In order to get the user’s credentials, you will need to ask for his permission. I went the easy route and asked directly for read/write access to Google Tasks, but you can get the list of scopes that can be used here. In order to be able to get the user’s token, you need to add the requestEmail permission.

Basically, the way the permission flow works is:

  1. Build a sign-in intent (with the desired permissions);
  2. Ask the system to fulfill the intent and wait for the response;
  3. Process the response

The code is quite straightforward:

Initializing the Google Tasks API

In order to initialize the Google Tasks API, you will need 3 things:

  • A JSONFactory
    I went with an instance of com.google.api.client.json.jackson2.JacksonFactory simply because it was there and worked
  • HttpTransport
    Depending on the Android version you are targeting, you must use a different class. Using AndroidHttp.newCompatibleTransport() makes this selection transparent.
  • The user’s credentials

Interacting with Google Tasks on Android

Once you got the Tasks Service in your hands, interacting with it is the same as doing so in Java. Since I’ve been using API 23, I can’t use streams like I used in my java example. Therefore, I did two little helpers ( TaskList findTaskList(TaskLists tasklists, String title)  and Task findTask(Tasks tasks, String title)).

Creating a task list

Finding a task list

Creating a task

Finding a task

Updating a task

Completing a task

Handling a large number of return values

Like any good online service, Google Tasks API handles a large number of values using pagination. By default, most APIs will return a maximum of 100 results. You are allowed to change this value, but in order to get good performance, you should not put it bigger.

Basically, the way to handle pagination is: do your normal call, check if you got a page token and if you do you know there are more results waiting. You can then call the API again with the page token in order to get the next result set:

Sources

Interacting with Google Tasks using Java

I already did a post giving an overview of interacting with Google Tasks using Ruby, but with the change in scope of my project, I now need to do the same in Java. Therefore, here is an overview of interacting with Google Tasks using Java. Do note that this probably won’t work on Android, it is meant to be used from Java Desktop editions.

Project Setup

Using gradle, the project setup is quite simple:

Google API Setup

In order to access Google Tasks using Java, you will need to use Google’s OAuth. Google’s OAuth uses what they call client secrets file. These files contain all the information needed to access the selected services.

To get a client secrets file, you can follow my other post.

Handling the user’s credentials

This project is my first Java project since a long time ago. I quickly remembered how painful it can be to play with the interface/abstract class hell. You have to instantiate 20 different things before calling anything and selecting the right implementation, or even simply finding an implementation, is sometimes tricky. Here, I selected the following implementations:

  • JsonFactory: com.google.api.client.json.jackson2.JacksonFactory, it was there and worked, so I used it;
  • HttpTransportcom.google.api.client.http.javanet.NetHttpTransport, according to the API’s documentation “NetHttpTransport is based on the HttpURLConnection built into the Java SDK, so it is normally the preferred choice“;
  • DataStoreFactorycom.google.api.client.util.store.FileDataStoreFactory, this implementation will store the tokens in a file (Ok … multiple files …). In my case, it will be in a directory called tokens in the current working directory;

Here is the authentication code I used. It will take care of caching the tokens, opening the browser if a new token is needed and getting the result token.

Initializing the Google Tasks API

In order to use the Google Tasks API, you need to build the service. Doing so requires most of the things that were initialized in the previous section:

Interacting with Google Tasks using Java

Creating a task list

Once you have all the boilerplate done for the initialization of the API and the service, creating a tasklist becomes quite easy:

Finding a task list

The Google Tasks API only allows you to search by tasklist ID, not a title. This ID is automatically generated and therefore not really easy to use. The easiest way to find a task list is to list all task lists and find the one you are looking for in there:

Creating a task

In order to create a task, you first need a tasklist. Once you got that, creating the task is easy enough:

Finding a task

Just like finding a tasklist, you can’t directly search by task title. Therefore, you need to go iterate over the full list to find the one you are looking for:

Updating a task

Once you have a task (and a tasklist) in your hands, updating most of its fields can be done directly on the Task instance. The following example updates the due date of a task:

Completing a task

Just like updating a task, completing it is quite easy: set its status field to completed:

Handling a large number of return values

Like any good online service, Google Tasks API handles a large number of values using pagination. By default, most APIs will return a maximum of 100 results. You are allowed to change this value, but in order to get good performance, you should not put it bigger.

Basically, the way to handle pagination is: do your normal call, check if you got a page token and if you do you know there are more results waiting. You can then call the API again with the page token in order to get the next result set:

 

Sources

Fix Eclipse not finding javax.annotation

I recently started playing with Java again and I had to get up to date with the recent tooling. Gradle was my first target. While playing with it, I got really annoyed at some point: I had a working Gradle build, but Eclipse was telling me that it could not find javax.annotation.CheckForNull and a few other friends. Here is how to fix Eclipse not finding javax.annotation.

In my case, some generated code I was using needed @Nonnull and @CheckForNull. Both of these were introduced in JSR-305 (aka Annotations for Software Defect Detection).

Step 1 – Ensure that you have the library

The easiest implementation I could find was the one shipped with FindBugs (com.google.code.findbugs:jsr305). In order to include this dependency into your project, simply modify your build.gradle file to add the following:

 

In my specific case, I was already using org.anarres.gradle:gradlesablecc-plugin:1.0.4, and this already requires jsr305. Therefore, I did not have to manually add it.

 

Figure 1: Gradle dependencies output

In order to validate your dependency, you can get the dependency tree from Gradle. To do so, get a command prompt open in your project root directory. In there, simply run: .\gradlew.bat dependencies –configuration testCompileClasspath. Since I am using other dependencies, the output from this command in my project is what is shown in figure 1.

 

Step 2 – Refresh your Eclipse project

This step is where I lost quite a bit of time …

If you are using Eclipse Buildship, you can refresh the project by simply right-clicking it, and in the menu hit Gradle->Refresh Gradle Project. This will update your Eclipse project to ensure that all classpath setting and other stuff is valid.

Sources

Fix Gradle Eclipse task ignoring JAVA_HOME

I started playing with Java again recently and lost quite a bit of time fixing a stupid issue: when running a Gradle task from Eclipse, Gradle was ignoring JAVA_HOME environment variable. Here is how I fixed that issue.

The issue

When installing Java 8, I decided to install both the JRE and the JDK (in that order). Looks like Java now creates a symlink from C:\ProgramData\Oracle\Java\javapath to your Java bin directory and puts that as the first entry in the PATH environment variable. Doing so makes your first Java installation be your default installation.

I could not find a clean way to modify this behavior or to change the path in C:\ProgramData\Oracle\Java\javapath. Yeah, sure, I could simply modify it or remove it from the path, but without being certain that it won’t break anything I did not want to change it.

As a second issue, it looks like Eclipse ignores the Gradle wrapper (gradlew.bat on windows) or eats the environment variable. If it was using the wrapper, you’d be able to change the Java used by using the JAVA_HOME environment variable.

The fix

I decided to go the easy route and simply add my java installation into the path (as the first entry). I really don’t like this solution, it pollutes my path and prevents me from easily switching. I’ll continue to investigate why Eclipse eats the configuration and update this post (or link to a new one) once I get something cleaner.

Sources