website: Update diceroller and syncbase guides to 0.1.7

Lots of code changes from 0.1.4 to 0.1.7

I spot checked by running `make serve` locally. (If you pull down
this patchset, you can do the same by running `make serve`)

I will likely `make deploy` after this CL is submitted.

Note: We are working on 0.1.8 right now, but the website depends on
what has already been published. This repo will generally be a little
behind master, which is expected.

Change-Id: Iec284ef1e105c2d1540ff08cc7939355ad6a0820
diff --git a/Makefile b/Makefile
index fa24d44..c42823f 100644
--- a/Makefile
+++ b/Makefile
@@ -382,6 +382,7 @@
 
 # An ordering that lets us test all the Java tutorials faster than running the
 # individual tests in sequence.
+# depsOneBigSyncbaseAndroidTest = content/$(syncbaseAndroidDataSync).md
 depsOneBigSyncbaseAndroidTest = \
 	content/$(syncbaseAndroidQuickstart).md \
 	content/$(syncbaseAndroidFirstApp).md \
@@ -467,6 +468,6 @@
 # jiri cl mail
 .PHONY: upgrade-syncbase-android
 # Change this to the desired version before running the target.
-SYNCBASE_ANDROID_VERSION=0.1.4
+SYNCBASE_ANDROID_VERSION=0.1.7
 upgrade-syncbase-android:
 	find content/syncbase -type f -exec sed -i "s/\(compile 'io.v:syncbase:\)\(.*\)'/\1$(SYNCBASE_ANDROID_VERSION)'/g" {} \;
\ No newline at end of file
diff --git a/content/syncbase/first-app.md b/content/syncbase/first-app.md
index 2000244..5792b4d 100644
--- a/content/syncbase/first-app.md
+++ b/content/syncbase/first-app.md
@@ -43,7 +43,7 @@
 ```
 cat - <<EOF >> $PROJECT_DIR/app/build.gradle
 dependencies {
-  compile 'io.v:syncbase:0.1.4'
+  compile 'io.v:syncbase:0.1.7'
 }
 EOF
 ```
@@ -70,39 +70,61 @@
 {{# helpers.codedim }}
 package io.v.syncbase.example;
 
-import android.support.v7.app.AppCompatActivity;
-
+import android.content.Context;
 import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
 import android.util.Log;
 {{/ helpers.codedim }}
-import io.v.syncbase.*;
+import io.v.syncbase.Syncbase;
+import io.v.syncbase.exception.SyncbaseException;
 
 {{# helpers.codedim }}
 public class MainActivity extends AppCompatActivity {
+  private static final String TAG = "DiceRoller";
+
+  // Note: You can replace CLOUD_NAME and CLOUD_ADMIN with your cloud syncbase
+  // name and blessing from https://sb-allocator.v.io
+  private static final String CLOUD_NAME =
+      "/(dev.v.io:r:vprod:service:mounttabled)@ns.dev.v.io:8101/sb/syncbased-24204641";
+  private static final String CLOUD_ADMIN = "dev.v.io:r:allocator:us:x:syncbased-24204641";
+  private static final String MOUNT_POINT = "/ns.dev.v.io:8101/tmp/diceroller/users";
 
   @Override
   protected void onCreate(Bundle savedInstanceState) {
-
     super.onCreate(savedInstanceState);
-    {{/ helpers.codedim }}
-
-    Syncbase.DatabaseOptions options = new Syncbase.DatabaseOptions();
-    // dbOpt.cloudSyncbaseAddress = "<Your Cloud Syncbase Address>";
-    // dbOpt.cloudSyncbaseBlessing = "<Your Cloud Syncbase Blessing>";
-
-    Syncbase.database(new Syncbase.DatabaseCallback() {
-        @Override
-        public void onSuccess(final Database db) {
-
-           // Use database to interact with Syncbase.
-
-           Log.i("info", "Syncbase is ready");
-        }
-    }, options);
-
-    {{# helpers.codedim }}
     setContentView(R.layout.activity_main);
+    {{/ helpers.codedim }}
+    try {
+        String rootDir = getDir("syncbase", Context.MODE_PRIVATE).getAbsolutePath();
+        Syncbase.Options options =
+                Syncbase.Options.cloudBuilder(rootDir, CLOUD_NAME, CLOUD_ADMIN)
+                        .setMountPoint(MOUNT_POINT).build();
+        Syncbase.init(options);
+    } catch (SyncbaseException e) {
+        Log.e(TAG, "Syncbase failed to initialize", e);
+    }
+
+    Syncbase.loginAndroid(this, new LoginCallback());
   }
+
+  @Override
+  protected void onDestroy() {
+      Syncbase.shutdown();
+      super.onDestroy();
+  }
+
+  private class LoginCallback implements Syncbase.LoginCallback {
+    @Override
+    public void onSuccess() {
+        Log.i(TAG, "Syncbase is ready");
+    }
+
+    @Override
+    public void onError(Throwable e) {
+        Log.e(TAG, "Syncbased failed to login", e);
+    }
+  }
+  {{# helpers.codedim }}
 }
 {{/ helpers.codedim }}
 EOF
@@ -175,7 +197,7 @@
 {{/ helpers.hidden }}
 
 # Data Binding
-The data model for this app is simple. We just need a single collection (`dice`)
+The data model for this app is simple. We just need a single collection
 and a single key/value pair (`'result'`, `int`) to store the result of the dice
 roll.
 
@@ -198,8 +220,9 @@
 {{# helpers.codedim }}
 package io.v.syncbase.example;
 
-import android.support.v7.app.AppCompatActivity;
+import android.content.Context;
 import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
 import android.util.Log;
 import android.view.View;
 import android.widget.Button;
@@ -208,77 +231,123 @@
 import java.util.Iterator;
 import java.util.Random;
 
-import io.v.syncbase.*;
+import io.v.syncbase.Collection;
+import io.v.syncbase.Database;
+import io.v.syncbase.Syncbase;
+import io.v.syncbase.WatchChange;
+import io.v.syncbase.exception.SyncbaseException;
 
 public class MainActivity extends AppCompatActivity {
+    private static final String TAG = "DiceRoller";
+    {{/ helpers.codedim }}
+    private static final String RESULT_KEY = "result";
+    {{# helpers.codedim }}
+
+    // Note: Replace CLOUD_NAME and CLOUD_ADMIN with your cloud syncbase name
+    // and blessing from https://sb-allocator.v.io
+    private static final String CLOUD_NAME = "<cloud name>";
+    private static final String CLOUD_ADMIN = "<cloud admin>";
+    private static final String MOUNT_POINT = "/ns.dev.v.io:8101/tmp/diceroller/users";
 
   @Override
   protected void onCreate(Bundle savedInstanceState) {
-
     super.onCreate(savedInstanceState);
+    setContentView(R.layout.activity_main);
 
-    Syncbase.DatabaseOptions options = new Syncbase.DatabaseOptions();
-    // dbOpt.cloudSyncbaseAddress = "<Your Cloud Syncbase Address>";
-    // dbOpt.cloudSyncbaseBlessing = "<Your Cloud Syncbase Blessing>";
+    try {
+      String rootDir = getDir("syncbase", Context.MODE_PRIVATE).getAbsolutePath();
+      Syncbase.Options options =
+          Syncbase.Options.cloudBuilder(rootDir, CLOUD_NAME, CLOUD_ADMIN)
+              .setMountPoint(MOUNT_POINT).build();
+      Syncbase.init(options);
+    } catch (SyncbaseException e) {
+      Log.e(TAG, "Syncbase failed to initialize", e);
+    }
 
-    Syncbase.database(new Syncbase.DatabaseCallback() {
-      @Override
-      public void onSuccess(final Database db) {
+    Syncbase.loginAndroid(this, new LoginCallback());
+  }
 
-        // Use database to interact with Syncbase.
+  @Override
+  protected void onDestroy() {
+    Syncbase.shutdown();
+    super.onDestroy();
+  }
+{{/ helpers.codedim }}
 
-        Log.i("info", "Syncbase is ready");
-        {{/ helpers.codedim }}
+  private class LoginCallback implements Syncbase.LoginCallback {
+    @Override
+    public void onSuccess() {
+      Log.i(TAG, "Syncbase is ready");
 
-        // On dice roll, put a new random number under key "result"
-        // in the "dice" collection.
-        final Button button = (Button) findViewById(R.id.buttonRoll);
+      try {
+        final Collection userdata = Syncbase.database().getUserdataCollection();
+
+        // On dice roll, put a random number into the userdata collection under RESULT_KEY.
+        final View button = findViewById(R.id.buttonRoll);
+        if (button == null) {
+          Log.e(TAG, "Resource not found: " + R.id.buttonRoll);
+          return;
+        }
+        button.setEnabled(true);
         button.setOnClickListener(new View.OnClickListener() {
-          public void onClick(View v) {
-            int randomNumber =  new Random().nextInt(6) + 1;
+          private Random random = new Random();
 
-            Collection diceCollection = db.collection("dice");
-            diceCollection.put("result", randomNumber);
+          @Override
+          public void onClick(View v) {
+            int randomNumber = random.nextInt(6) + 1;
+            try {
+              userdata.put(RESULT_KEY, randomNumber);
+            } catch (SyncbaseException e) {
+              Log.e(TAG, "put error", e);
+            }
           }
         });
 
-        // Watch the database and update the UI whenever a new value
-        // is encountered.
-        db.addWatchChangeHandler(new Database.WatchChangeHandler() {
+        Syncbase.database().addWatchChangeHandler(new Database.WatchChangeHandler() {
           @Override
           public void onInitialState(Iterator<WatchChange> values) {
-            // onInitialState is called with any existing data in Syncbase.
-            // Since we only have a single collection, single key/value,
-            // there can only be 0 or 1 values.
-            if (values.hasNext()) {
-              int result = (int) values.next().getValue();
-              updateResult(result);
-            }
+            onChange(values);
           }
 
           @Override
           public void onChangeBatch(Iterator<WatchChange> changes) {
-            // onChangeBatch is called with any updates to the data.
-            // Since we only have a single collection, single key/value.
-            // there can only be 1 WatchChange whenever the value is mutated
-            // and the type of change would always be `put` in our case.
-            int result = (int) changes.next().getValue();
-            updateResult(result);
+            onChange(changes);
           }
 
           @Override
           public void onError(Throwable e) {
-            // Something went wrong. Watch is no longer active.
+            Log.e(TAG, "watch error", e);
           }
-        }, new Database.AddWatchChangeHandlerOptions());
-        {{# helpers.codedim }}
-      }
-    }, new Syncbase.DatabaseOptions());
 
-    setContentView(R.layout.activity_main);
+          private void onChange(Iterator<WatchChange> changes) {
+            while (changes.hasNext()) {
+              WatchChange watchChange = changes.next();
+              Log.i(TAG, "Received watch change: " + watchChange.toString());
+              if (watchChange.getCollectionId().getName().equals(
+                  Syncbase.USERDATA_NAME) &&
+                  watchChange.getEntityType() == WatchChange.EntityType.ROW &&
+                  watchChange.getChangeType() == WatchChange.ChangeType.PUT &&
+                  watchChange.getRowKey().equals(RESULT_KEY)) {
+                try {
+                  updateResult(watchChange.getValue(Integer.class));
+                } catch (SyncbaseException e) {
+                  Log.e(TAG, "watch change error", e);
+                }
+              }
+            }
+          }
+        });
+      } catch (SyncbaseException e) {
+        Log.e(TAG, "Syncbased failed to login", e);
+      }
+    }
+
+    @Override
+    public void onError(Throwable e) {
+        Log.e(TAG, "LoginCallback: onError", e);
+    }
   }
 
-{{/ helpers.codedim }}
   private void updateResult(int newValue) {
     final TextView result = (TextView) findViewById(R.id.textViewResult);
     result.setText(String.valueOf(newValue));
diff --git a/content/syncbase/guides/batches.md b/content/syncbase/guides/batches.md
index 7a24cf2..f83500c 100644
--- a/content/syncbase/guides/batches.md
+++ b/content/syncbase/guides/batches.md
@@ -13,15 +13,19 @@
 cp -r $JIRI_ROOT/website/tools/android_project_stubs/example/* $PROJECT_DIR
 cat - <<EOF >> $PROJECT_DIR/app/build.gradle
 dependencies {
-  compile 'io.v:syncbase:0.1.4'
+  compile 'io.v:syncbase:0.1.7'
 }
 EOF
 cat - <<EOF > $FILE
 package io.v.syncbase.example;
-import io.v.syncbase.*;
+import io.v.syncbase.Collection;
+import io.v.syncbase.BatchDatabase;
+import io.v.syncbase.Database;
+import io.v.syncbase.Syncbase;
+import io.v.syncbase.exception.SyncbaseException;
 public class Batches {
   Database db;
-  void main() {
+  void main() throws SyncbaseException {
 EOF
 ```
 {{/ helpers.hidden }}
@@ -86,9 +90,9 @@
 cat - <<EOF | sed 's/{{.*}}//' >> $FILE
 db.runInBatch(new Database.BatchOperation() {
   @Override
-  public void run(BatchDatabase batchDb) {
-    Collection c1 = batchDb.collection("collection1");
-    Collection c2 = batchDb.collection("collection2");
+  public void run(BatchDatabase batchDb) throws SyncbaseException {
+    Collection c1 = batchDb.createCollection();
+    Collection c2 = batchDb.createCollection();
 
     c1.put("myKey", "myValue");
     c2.put("myKey", "myValue");
@@ -121,13 +125,12 @@
 ```Java
 cat - <<EOF | sed 's/{{.*}}//' >> $FILE
 // WRONG: c1 is NOT part of the batch.
-final Collection c1 = db.collection("collection1");
+final Collection c1 = db.createCollection();
 {{# helpers.codedim }}
 db.runInBatch(new Database.BatchOperation() {
     @Override
-    public void run(BatchDatabase batchDb) {
-
-        Collection c2 = batchDb.collection("collection2");
+    public void run(BatchDatabase batchDb) throws SyncbaseException {
+        Collection c2 = batchDb.createCollection();
         {{/ helpers.codedim }}
         // WRONG: Only mutations on c2 are atomic since c1 reference
         // was obtained from Database and not BatchDatabase.
@@ -167,8 +170,8 @@
 cat - <<EOF | sed 's/{{.*}}//' >> $FILE
 BatchDatabase batchDb = db.beginBatch(new Database.BatchOptions());
 
-Collection c1 = batchDb.collection("collection1");
-Collection c2 = batchDb.collection("collection2");
+Collection c1 = batchDb.createCollection();
+Collection c2 = batchDb.createCollection();
 
 c1.put("myKey", "myValue");
 c2.put("myKey", "myValue");
@@ -205,12 +208,12 @@
 ```Java
 cat - <<EOF | sed 's/{{.*}}//' >> $FILE
 // WRONG: c1 is NOT part of the batch.
-Collection c1 = db.collection("collection1");
+Collection c1 = db.createCollection();
 {{# helpers.codedim }}
 BatchDatabase batchDb = db.beginBatch(new Database.BatchOptions());
 
 // c2 is part of the batch.
-Collection c2 = batchDb.collection("collection2");
+Collection c2 = batchDb.createCollection();
 {{/ helpers.codedim }}
 
 // WRONG: Only mutations on c2 are atomic since c1 reference was obtained
diff --git a/content/syncbase/guides/data-flow.md b/content/syncbase/guides/data-flow.md
index e14bf12..7bc5ab8 100644
--- a/content/syncbase/guides/data-flow.md
+++ b/content/syncbase/guides/data-flow.md
@@ -13,19 +13,24 @@
 cp -r $JIRI_ROOT/website/tools/android_project_stubs/example/* $PROJECT_DIR
 cat - <<EOF >> $PROJECT_DIR/app/build.gradle
 dependencies {
-  compile 'io.v:syncbase:0.1.4'
+  compile 'io.v:syncbase:0.1.7'
 }
 EOF
 cat - <<EOF > $FILE
 package io.v.syncbase.example;
-import io.v.syncbase.*;
+import io.v.syncbase.Collection;
+import io.v.syncbase.Database;
+import io.v.syncbase.Syncbase;
+import io.v.syncbase.WatchChange;
+import io.v.syncbase.exception.SyncbaseException;
+import android.util.Log;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 public class DataFlow {
   Database db;
   class Task {}
-  void main() {
+  void main() throws SyncbaseException {
 EOF
 ```
 {{/ helpers.hidden }}
@@ -66,7 +71,6 @@
 
   @Override
   public void onInitialState(Iterator<WatchChange> values) {
-
     // onInitialState is called with all of existing data in Syncbase.
     // Although the value type is WatchChange, since this is existing
     // data, there will not be any values with ChangeType == DELETE_CHANGE
@@ -79,7 +83,6 @@
 
   @Override
   public void onChangeBatch(Iterator<WatchChange> changes) {
-
     // onChangeBatch is called whenever changes are made to the data.
     // Changes that are part of the same batch are presented together,
     // otherwise changes iterator may only contain a single change.
@@ -89,7 +92,12 @@
 
     // Trigger UI update
   }
-}, new Database.AddWatchChangeHandlerOptions());
+
+  @Override
+  public void onError(Throwable t) {
+    // Handle error
+  }
+});
 EOF
 ```
 
@@ -110,23 +118,23 @@
 
 // Update the state based on the changes.
 void updateState(WatchChange change) {
-
+  try {
     String collectionId = change.getCollectionId().encode();
     String rowKey = change.getRowKey();
 
     if(change.getChangeType() == WatchChange.ChangeType.PUT) {
-
       if(!state.containsKey(collectionId)) {
         state.put(collectionId, new HashMap<String, Task>());
       }
-      Task rowValue = (Task)change.getValue();
+      Task rowValue = change.getValue(Task.class);
       state.get(collectionId).put(rowKey, rowValue);
 
     } else if(change.getChangeType() == WatchChange.ChangeType.DELETE) {
-
       state.get(collectionId).remove(rowKey);
-
     }
+  } catch (SyncbaseException e) {
+    Log.e("DataFlowExample", "update state error", e);
+  }
 }
 EOF
 ```
diff --git a/content/syncbase/guides/data-model.md b/content/syncbase/guides/data-model.md
index e7c1dc4..2f6ddd4 100644
--- a/content/syncbase/guides/data-model.md
+++ b/content/syncbase/guides/data-model.md
@@ -13,18 +13,22 @@
 cp -r $JIRI_ROOT/website/tools/android_project_stubs/example/* $PROJECT_DIR
 cat - <<EOF >> $PROJECT_DIR/app/build.gradle
 dependencies {
-  compile 'io.v:syncbase:0.1.4'
+  compile 'io.v:syncbase:0.1.7'
 }
 EOF
 cat - <<EOF > $FILE
 package io.v.syncbase.example;
-import io.v.syncbase.*;
+import io.v.syncbase.Collection;
+import io.v.syncbase.Database;
+import io.v.syncbase.Syncbase;
+import io.v.syncbase.exception.SyncbaseException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
+
 public class DataModel {
   Database db;
-  void main() {
+  void main() throws SyncbaseException {
 EOF
 ```
 {{/ helpers.hidden }}
@@ -34,7 +38,9 @@
 blobs. The data is organized by the following hierarchy:
 
 * [Database](#database): An app is pre-configured to have a single database
-which may contain any number of collections.
+which may contain any number of collections. When configured with a cloud, the
+database also comes with a `userdata` collection, synced across the same user's
+devices.
 * [Collection](#collections): A collection is a set of key-value pairs
 (rows). Collections are the unit of access control and sharing.
 * [Row](#rows): Each row contains a single key-value pair. Keys are strings and
@@ -48,22 +54,16 @@
 Database is the entry point to the Syncbase API and provides functionality to
 create, watch and share collections, and to perform batch operations.
 
-There is a pre-configured database for each app. `Syncbase.getDatabase()` is
-used to initialize Syncbase and get a reference to the app's database.
+There is a pre-configured database for each app. `Syncbase.database()` is
+used to get a reference to the app's database. This may be called any number of
+times after initializing Syncbase and logging in.
 
 <!-- @createDatabase @test -->
 ```
 cat - <<EOF >> $FILE
-Syncbase.DatabaseOptions options = new Syncbase.DatabaseOptions();
-// dbOpt.cloudSyncbaseAddress = "<Your Cloud Syncbase Address>";
-// dbOpt.cloudSyncbaseBlessing = "<Your Cloud Syncbase Blessing>";
 
-Syncbase.database(new Syncbase.DatabaseCallback() {
-  @Override
-  public void onSuccess(final Database db) {
-    // Use database to interact with Syncbase.
-  }
-}, options);
+// After Syncbase.init and login...
+Database database = Syncbase.database();
 EOF
 ```
 
@@ -91,20 +91,12 @@
 
 Collections created by all users live in the same namespace. To avoid collisions,
 the system automatically prepends the user's identity (blessing) to the
-Collection ID. The developer still needs to think about collisions, however.
-The user might use one device while offline and then switch to another device
-while still offline. When those two devices sync with each other, should the
-Collections merge or stay separate? If the developer wants them to stay separate,
-the collection IDs should include a UUID. If the developer wants them to merge,
-they should use a predictable name (example: "preferences"). Collection names
-are restricted to alphanumeric characters plus underscore and can have a maximum
-length of 64 bytes.
+Collection ID as well as adds a UUID to each collection name.
 
 <!-- @createCollection @test -->
 ```
 cat - <<EOF >> $FILE
-String collectionName = UUID.randomUUID().toString();
-Collection collection = db.collection(collectionName);
+Collection collection = db.createCollection();
 
 String rowKey = UUID.randomUUID().toString();
 collection.put(rowKey, "myValue");
@@ -118,7 +110,23 @@
 As mentioned earlier, collections are synced across user's devices by default
 but one can set `withoutSyncgroup` to `false` on
 `CollectionOptions` to make a local-only collection that will not sync with
-any other peer.
+any other peer. The `CollectionOptions` also allow a collection name prefix to
+be specified to help differentiate between different types of collections. One
+can also access the database's `userdata` collection.
+
+<!-- @userdataCollection @test -->
+```
+cat - <<EOF >> $FILE
+Collection userdata = db.getUserdataCollection();
+
+Database.CollectionOptions options =
+    new Database.CollectionOptions()
+        .setWithoutSyncgroup(true)
+        .setPrefix("restaurants");
+Collection prefixedCollection = db.createCollection(options);
+
+EOF
+```
 
 [Collection API reference](/syncbase/api-reference.html#collection)
 
diff --git a/content/syncbase/guides/synchronization.md b/content/syncbase/guides/synchronization.md
index 6f0ec16..559cd2a 100644
--- a/content/syncbase/guides/synchronization.md
+++ b/content/syncbase/guides/synchronization.md
@@ -13,18 +13,25 @@
 cp -r $JIRI_ROOT/website/tools/android_project_stubs/example/* $PROJECT_DIR
 cat - <<EOF >> $PROJECT_DIR/app/build.gradle
 dependencies {
-  compile 'io.v:syncbase:0.1.4'
+  compile 'io.v:syncbase:0.1.7'
 }
 EOF
 cat - <<EOF > $FILE
 package io.v.syncbase.example;
-import io.v.syncbase.*;
+import io.v.syncbase.AccessList;
+import io.v.syncbase.Collection;
+import io.v.syncbase.Database;
+import io.v.syncbase.Syncbase;
+import io.v.syncbase.Syncgroup;
+import io.v.syncbase.SyncgroupInvite;
+import io.v.syncbase.User;
+import io.v.syncbase.exception.SyncbaseException;
 import java.util.Iterator;
 public class DataSync {
   Database db;
   User userToInvite;
   User userToRemove;
-  void main() {
+  void main() throws SyncbaseException {
 EOF
 ```
 {{/ helpers.hidden }}
@@ -80,7 +87,7 @@
 <!-- @inviteUser @test -->
 ```
 cat - <<EOF >> $FILE
-Collection collectionToShare = db.collection("myCollection");
+Collection collectionToShare = db.createCollection();
 
 collectionToShare.getSyncgroup().inviteUser(userToInvite, AccessList.AccessLevel.READ);
 EOF
@@ -99,9 +106,19 @@
       public void onSuccess(Syncgroup sg) {
         // Accepting invitation was successful.
       }
+
+      @Override
+      public void onFailure(Throwable t) {
+        // Accepting invitation was unsuccessful.
+      }
     });
   }
-}, new Database.AddSyncgroupInviteHandlerOptions());
+
+  @Override
+  public void onError(Throwable t) {
+    // Invite handler error.
+  }
+});
 EOF
 ```
 
@@ -127,7 +144,7 @@
 <!-- @unshareCollection @test -->
 ```
 cat - <<EOF >> $FILE
-Collection sharedCollection = db.collection("myCollection");
+Collection sharedCollection = db.createCollection();
 
 sharedCollection.getSyncgroup().ejectUser(userToRemove);
 EOF
diff --git a/content/syncbase/quickstart.md b/content/syncbase/quickstart.md
index 2e43da4..b53c0f1 100644
--- a/content/syncbase/quickstart.md
+++ b/content/syncbase/quickstart.md
@@ -35,7 +35,7 @@
 ```
 cat - <<EOF >> $PROJECT_DIR/app/build.gradle
 dependencies {
-  compile 'io.v:syncbase:0.1.4'
+  compile 'io.v:syncbase:0.1.7'
 }
 EOF
 ```
@@ -62,38 +62,60 @@
 {{# helpers.codedim}}
 package io.v.syncbase.example;
 
-import android.support.v7.app.AppCompatActivity;
+import android.content.Context;
 import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
 {{/ helpers.codedim}}
-import io.v.syncbase.*;
+import io.v.syncbase.Collection;
+import io.v.syncbase.Syncbase;
+import io.v.syncbase.exception.SyncbaseException;
 
 {{# helpers.codedim}}
 public class MainActivity extends AppCompatActivity {
+    private static final String TAG = "QuickStart";
+
+    // Note: Replace CLOUD_NAME and CLOUD_ADMIN with your cloud syncbase name
+    // and blessing from https://sb-allocator.v.io
+    private static final String CLOUD_NAME = "<cloud name>";
+    private static final String CLOUD_ADMIN = "<cloud admin>";
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        {{/ helpers.codedim}}
-        Syncbase.DatabaseOptions options = new Syncbase.DatabaseOptions();
-        // dbOpt.cloudSyncbaseAddress = "<Your Cloud Syncbase Address>";
-        // dbOpt.cloudSyncbaseBlessing = "<Your Cloud Syncbase Blessing>";
-
-        Syncbase.database(new Syncbase.DatabaseCallback() {
-            @Override
-            public void onSuccess(final Database db) {
-
-                // Use database to interact with Syncbase.
-
-                Collection collection = db.collection("myCollection");
-
-                collection.put("myKey", "myValue");
-
-                String value = collection.get("myKey", String.class);
-            }
-        }, options);
-        {{# helpers.codedim}}
-
         setContentView(R.layout.activity_main);
+        {{/ helpers.codedim}}
+        try {
+            String rootDir = getDir("syncbase", Context.MODE_PRIVATE).getAbsolutePath();
+            Syncbase.Options options =
+                    Syncbase.Options.cloudBuilder(rootDir, CLOUD_NAME, CLOUD_ADMIN)
+                            .build();
+            Syncbase.init(options);
+        } catch (SyncbaseException e) {
+            Log.e(TAG, "Syncbase failed to initialize", e);
+        }
+
+        Syncbase.loginAndroid(this, new Syncbase.LoginCallback() {
+            @Override
+            public void onSuccess() {
+                Log.i(TAG, "Syncbase is ready");
+
+                // Interact with syncbase!
+                try {
+                    Collection collection = Syncbase.database().createCollection();
+                    collection.put("myKey", "myValue");
+                    String value = collection.get("myKey", String.class);
+                } catch (SyncbaseException e) {
+                    Log.e(TAG, "Syncbase error", e);
+                }
+            }
+
+            @Override
+            public void onError(Throwable e) {
+                Log.e(TAG, "Syncbased failed to login", e);
+            }
+        });
+        {{# helpers.codedim}}
     }
 }
 {{/ helpers.codedim}}