Pebble

I signed up for the Pebble Kickstarter for a couple of reasons.

Firstly I actually wanted the watch – a waterproof watch that I could use to receive notifications without having to get the phone out of my pocket, and which I could use to control podcasts, audiobooks and music.

Secondly I wanted to be able to program it.  The full SDK is not yet available, so I can’t write programs that run on the watch, but it is possible to write Android apps that communicate with the watch.

I’ve spent some time today writing a small app that integrates the Pebble device with Evernote.

Evernote

One of the great things about Evernote is that it is very simple and easy to use at one level, but as your usage becomes more sophisticated, and your requirements deepen, you’ll find that it is much more powerful and capable than it first appears.

An example of this is that notes you create can optionally contain geolocation information, and you can view your notes on a map to see which ones you created on a particular vacation or business trip.

The idea

Vacation Location

I thought I’d use this Evernote Note geolocation capability to create an app that reminds you when you get close to the location associated with certain notes.

ColosseumAtEvening Imagine going on vacation and creating a series of notes in Evernote for particular locations that you want to visit.  Whenever you get close to one of those locations your Pebble buzzes and you are reminded to visit it.

Evernote Food graphicRestaurant Reminder

Or imagine using Evernote Food to remember restaurants you want to visit, and your watch buzzing with a reminder if you happen to be close to one of those restaurants when it is meal time

I decided to implement it by having my app look for notes that have geolocation information (lat/lon) and are tagged with a particular tag (“pebble”).

When the app starts, it looks for those notes and uses the Android proximity service to set up proximity alerts for the note locations.  Then when the app receives the proximity alert it sends the note title as notification to the watch and could launch that note in Evernote.

image

The app

 

photo

This code uses the raw Evernote API, however there is an excellent Evernote Android SDK available, and if you are building an Android app that uses Evernote you should definitely check it out.

package com.everpebble;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.*;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import com.evernote.edam.notestore.*;
import com.evernote.edam.type.*;
import com.evernote.edam.userstore.UserStore;
import com.evernote.thrift.protocol.TBinaryProtocol;
import com.evernote.thrift.transport.THttpClient;
import org.json.*;

import java.util.HashMap;
import java.util.Map;

public class Main extends Activity {

  private static final String evernoteHost = "sandbox.evernote.com";
  private static final String userStoreUrl = "https://" + evernoteHost + "/edam/user";
  private static final String TAG = "EverPebble";

  private static final String PROX_ALERT_INTENT = "com.everpebble.ProximityAlert";

  // Available from https://sandbox.evernote.com/api/DeveloperToken.action
  private static final String authToken = "TBS";

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    // Register for proximity events off the UI thread
    new Thread(new Runnable() {
      @Override
      public void run() {
        registerEvernoteProximityNotes();
      }
    }).start();
  }

  /**
   * Finds all notes tagged with a particular tag that have geolocation information, and registers for
   * Android proximity alerts when the phone gets close to those note locations
   */
  private void registerEvernoteProximityNotes() {
    THttpClient userStoreTrans;
    try {
      // Connect to Evernote to discover the note store URL
      userStoreTrans = new THttpClient(userStoreUrl);
      TBinaryProtocol userStoreProt = new TBinaryProtocol(userStoreTrans);
      UserStore.Client userStore = new UserStore.Client(userStoreProt, userStoreProt);
      String notestoreUrl = userStore.getNoteStoreUrl(authToken);

      // Set up the NoteStore client
      THttpClient noteStoreTrans = new THttpClient(notestoreUrl);
      TBinaryProtocol noteStoreProt = new TBinaryProtocol(noteStoreTrans);
      NoteStore.Client noteStore = new NoteStore.Client(noteStoreProt, noteStoreProt);

      // Find notes Tagged with "pebble" that have geolocation information
      NoteFilter noteFilter = new NoteFilter();
      noteFilter.setWords("tag:pebble latitude:* longitude:*");
      NoteList result = noteStore.findNotes(authToken, noteFilter, 0, 50);
      Log.i(TAG, "Found: " + result.getTotalNotes());

      // Register for proximity alerts
      LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
      for(Note note : result.getNotes()) {
        NoteAttributes attributes = note.getAttributes();
        if(attributes != null) {
          Intent intent = new Intent(PROX_ALERT_INTENT);
          
          // Save the note title and guid in the intent so that when we are close
          // we can send the title to the Pebble
          intent.putExtra("Title", note.getTitle());
          intent.putExtra("Guid", note.getGuid());
          PendingIntent proximityIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
          
          // We want to be notified when we are within 100 meters of the location
          double lat =attributes.getLatitude();
          double lon = attributes.getLongitude();
          locationManager.addProximityAlert(lat, lon,  100, -1, proximityIntent);
        }
      }

      // Ensure we receive the event intents
      IntentFilter filter = new IntentFilter(PROX_ALERT_INTENT);
      registerReceiver(new ProximityIntentReceiver(), filter);

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * Sends alerts to the pebble phone when entering within range of a note's geolocation
   */
  public class ProximityIntentReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
      Log.d(TAG, "Received proximity alert");
      boolean entering = intent.getBooleanExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);

      final String title = intent.getStringExtra("Title");

      if(entering && title != null) {
        new Thread(new Runnable() {
          @Override
          public void run() {
            sendAlertToPebble("Evernote", title + " is nearby");
          }
        }).start();
      }
    }
  }


  public void sendAlertToPebble(String title, String body) {
    Log.d(TAG, "sendAlertToPebble invoked");
    final Intent i = new Intent("com.getpebble.action.SEND_NOTIFICATION");

    final Map<String, Object> data = new HashMap<String, Object>();
    data.put("title", title);
    data.put("body", body);
    final JSONObject jsonData = new JSONObject(data);
    final String notificationData = new JSONArray().put(jsonData).toString();

    i.putExtra("messageType", "PEBBLE_ALERT");
    i.putExtra("sender", "EverPebble");
    i.putExtra("notificationData", notificationData);

    Log.d(TAG, "About to send a modal alert to Pebble: " + notificationData);
    sendBroadcast(i);
  }
}

Summary

It is very early days for the Pebble, but its been great fun using it, and even more fun programming to it by integrating it with Evernote

Disclaimer: I do work for Evernote, but this blog is entirely my personal private work.