TBR TODOs: Upgrade to version 2.1.3

- new syncgroup API
- new collection names/ids are allowed (though sam is still default)

Behavior: Can create lists offline, but... the creation is slow due
to https://github.com/vanadium/issues/issues/1326

Change-Id: I1dab1c556d66e57b18ec7ac6db5d516e388e3c85
diff --git a/app/build.gradle b/app/build.gradle
index b25aaf2..e0ce402 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -79,5 +79,5 @@
             'com.google.guava:guava:19.0'
     )
     firebaseCompile 'com.firebase:firebase-client-android:2.5.2'
-    syncbaseCompile 'io.v:vanadium-android:2.1.2'
+    syncbaseCompile 'io.v:vanadium-android:2.1.3'
 }
diff --git a/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbaseMain.java b/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbaseMain.java
index d487d33..d20c44e 100644
--- a/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbaseMain.java
+++ b/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbaseMain.java
@@ -87,24 +87,28 @@
                     Futures.catchingAsync(joinListSyncgroup(listId),
                             SyncgroupJoinFailedException.class, new
                                     AsyncFunction<SyncgroupJoinFailedException, SyncgroupSpec>() {
-                        public ListenableFuture<SyncgroupSpec> apply(@Nullable
-                                                                     SyncgroupJoinFailedException
-                                                                             input) throws
-                                Exception {
-                            Log.d(TAG, "Join failed. Sleeping and trying again: " + listId);
-                            return sExecutor.schedule(new Callable<SyncgroupSpec>() {
+                                        public ListenableFuture<SyncgroupSpec> apply(@Nullable
+                                                                                     SyncgroupJoinFailedException
+                                                                                             input) throws
+                                                Exception {
+                                            Log.d(TAG, "Join failed. Sleeping and trying again: "
+                                                    + listId);
+                                            return sExecutor.schedule(new Callable<SyncgroupSpec>
+                                                    () {
 
-                                @Override
-                                public SyncgroupSpec call() throws Exception {
-                                    Log.d(TAG, "Sleep done. Trying again: " + listId);
+                                                @Override
+                                                public SyncgroupSpec call() throws Exception {
+                                                    Log.d(TAG, "Sleep done. Trying again: " +
+                                                            listId);
 
-                                    // If this errors, then we will not get another chance to see
-                                    // this syncgroup until the app is restarted.
-                                    return joinListSyncgroup(listId).get();
-                                }
-                            }, RETRY_DELAY, TimeUnit.MILLISECONDS);
-                        }
-                    });
+                                                    // If this errors, then we will not get
+                                                    // another chance to see
+                                                    // this syncgroup until the app is restarted.
+                                                    return joinListSyncgroup(listId).get();
+                                                }
+                                            }, RETRY_DELAY, TimeUnit.MILLISECONDS);
+                                        }
+                                    });
 
                     MainListTracker listTracker = new MainListTracker(getVContext(), getDatabase(),
                             listId, listener);
@@ -138,22 +142,28 @@
     public void addTodoList(final ListSpec listSpec) {
         final String listName = LISTS_PREFIX + mIdGenerator.generateTailId();
         final Collection listCollection = getDatabase().getCollection(getVContext(), listName);
+
+        // TODO(alexfandrianto): Syncgroup creation is slow if you specify a cloud and are offline.
+        // We'll try to connect to the cloud and then time out our RPC. The error is swallowed, so
+        // we'll just think there's a blank space of time. Maybe we should just write to these
+        // collections anyway. If https://github.com/vanadium/issues/issues/1326 is done, however,
+        // we won't need to change this code.
         Futures.addCallback(listCollection.create(getVContext(), null),
                 new TrappingCallback<Void>(getErrorReporter()) {
                     @Override
                     public void onSuccess(@Nullable Void result) {
                         Futures.addCallback(createListSyncgroup(listCollection.id()),
                                 new TrappingCallback<Void>(getErrorReporter()) {
-                            @Override
-                            public void onSuccess(@Nullable Void result) {
-                                // These can happen in either order.
-                                trap(getUserCollection().put(getVContext(), listName, null,
-                                        VdlAny.class));
-                                trap(listCollection.put(getVContext(),
-                                        SyncbaseTodoList.LIST_METADATA_ROW_NAME, listSpec,
-                                        ListSpec.class));
-                            }
-                        });
+                                    @Override
+                                    public void onSuccess(@Nullable Void result) {
+                                        // These can happen in either order.
+                                        trap(getUserCollection().put(getVContext(), listName, null,
+                                                VdlAny.class));
+                                        trap(listCollection.put(getVContext(),
+                                                SyncbaseTodoList.LIST_METADATA_ROW_NAME, listSpec,
+                                                ListSpec.class));
+                                    }
+                                });
                     }
                 });
     }
@@ -161,7 +171,9 @@
     private ListenableFuture<SyncgroupSpec> joinListSyncgroup(String listId) {
         SyncgroupMemberInfo memberInfo = getDefaultMemberInfo();
         String sgName = computeListSyncgroupName(listId);
-        return getDatabase().getSyncgroup(sgName).join(getVContext(), memberInfo);
+        String blessingStr = getPersonalBlessingsString(getVContext());
+        return getDatabase().getSyncgroup(new Id(blessingStr, sgName)).join(getVContext(),
+                CLOUD_NAME, CLOUD_BLESSING, memberInfo);
     }
 
     private ListenableFuture<Void> createListSyncgroup(Id id) {
@@ -173,10 +185,12 @@
         SyncgroupMemberInfo memberInfo = getDefaultMemberInfo();
 
         SyncgroupSpec spec = new SyncgroupSpec(
-                "TODOs User Data Collection", permissions,
+                "TODOs User Data Collection", CLOUD_NAME, permissions,
                 ImmutableList.of(new CollectionRow(id, "")),
                 ImmutableList.of(MOUNTPOINT), false);
-        return getDatabase().getSyncgroup(sgName).create(getVContext(), spec, memberInfo);
+        String blessingStr = getPersonalBlessingsString(getVContext());
+        return getDatabase().getSyncgroup(new Id(blessingStr, sgName)).create(getVContext(),
+                spec, memberInfo);
     }
 
     @Override
diff --git a/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbasePersistence.java b/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbasePersistence.java
index 455f637..4e0d795 100644
--- a/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbasePersistence.java
+++ b/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbasePersistence.java
@@ -52,6 +52,7 @@
 import io.v.v23.security.access.Constants;
 import io.v.v23.security.access.Permissions;
 import io.v.v23.services.syncbase.CollectionRow;
+import io.v.v23.services.syncbase.Id;
 import io.v.v23.services.syncbase.SyncgroupJoinFailedException;
 import io.v.v23.services.syncbase.SyncgroupMemberInfo;
 import io.v.v23.services.syncbase.SyncgroupSpec;
@@ -77,8 +78,8 @@
             PROXY = "proxy",
             DATABASE = "db",
             BLESSINGS_KEY = "blessings",
-            USER_COLLECTION_SYNCGROUP_SUFFIX = "/%%sync/sg_",
-            LIST_COLLECTION_SYNCGROUP_SUFFIX = "/%%sync/list_",
+            USER_COLLECTION_SYNCGROUP_SUFFIX = "sg_",
+            LIST_COLLECTION_SYNCGROUP_SUFFIX = "list_",
             DEFAULT_BLESSING_STRING = "dev.v.io:o:608941808256-43vtfndets79kf5hac8ieujto8837660" +
                     ".apps.googleusercontent.com:";
     protected static final long
@@ -88,8 +89,8 @@
             USER_COLLECTION_NAME = "userdata",
             MOUNTPOINT = "/ns.dev.v.io:8101/tmp/todos/users/",
             CLOUD_NAME = MOUNTPOINT + "cloud",
-            // TODO(alexfandrianto): This shouldn't be me running the cloud.
-            CLOUD_BLESSING = "dev.v.io:u:alexfandrianto@google.com";
+    // TODO(alexfandrianto): This shouldn't be me running the cloud.
+    CLOUD_BLESSING = "dev.v.io:u:alexfandrianto@google.com";
 
     // BlessingPattern initialization has to be deferred until after V23 init due to native binding.
     private static final Supplier<AccessList> OPEN_ACL = Suppliers.memoize(
@@ -187,6 +188,10 @@
         return V.getPrincipal(ctx).blessingStore().defaultBlessings();
     }
 
+    protected static String getPersonalBlessingsString(VContext ctx) {
+        return getPersonalBlessings(ctx).toString();
+    }
+
     protected static String getEmailFromBlessings(Blessings blessings) {
         String[] split = blessings.toString().split(":");
         return split[split.length - 1];
@@ -243,21 +248,8 @@
     private static void ensureUserCollectionExists() throws VException {
         synchronized (sUserCollectionMutex) {
             if (sUserCollection == null) {
-                // The reason the following doesn't work yet is that collections cross-share.
-                // https://github.com/vanadium/issues/issues/1320
-                //Collection userCollection = sDatabase.getCollection(sVContext,
-                //        USER_COLLECTION_NAME);
-
-                // The reason the following workaround doesn't work is the blessing is too long.
-                // https://github.com/vanadium/issues/issues/1322
-                // Collection userCollection = sDatabase.getCollection(
-                //        new Id(getPersonalBlessings(sVContext).toString(), USER_COLLECTION_NAME));
-
-                // TODO(alexfandrianto): Replace this with one of the above solutions when possible.
-                // This solution is forced to use the email and replace invalid characters.
-                String email = getPersonalEmail(sVContext).replace(".", "_").replace("@", "_AT_");
-                Collection userCollection = sDatabase.getCollection(sVContext,
-                        USER_COLLECTION_NAME + "_" + email);
+                Collection userCollection = sDatabase.getCollection(
+                        new Id(getPersonalBlessingsString(sVContext), USER_COLLECTION_NAME));
                 try {
                     VFutures.sync(userCollection.create(sVContext, null));
                 } catch (ExistException e) {
@@ -302,19 +294,20 @@
 
                 Permissions permissions = computePermissionsFromBlessings(clientBlessings);
 
-                String sgName = CLOUD_NAME + USER_COLLECTION_SYNCGROUP_SUFFIX + email;
+                String sgName = USER_COLLECTION_SYNCGROUP_SUFFIX + Math.abs(email.hashCode());
 
                 final SyncgroupMemberInfo memberInfo = getDefaultMemberInfo();
-                final Syncgroup sgHandle = sDatabase.getSyncgroup(sgName);
+                final Syncgroup sgHandle = sDatabase.getSyncgroup(new Id(clientBlessings.toString
+                        (), sgName));
 
                 try {
                     Log.d(TAG, "Trying to join the syncgroup: " + sgName);
-                    VFutures.sync(sgHandle.join(sVContext, memberInfo));
+                    VFutures.sync(sgHandle.join(sVContext, CLOUD_NAME, CLOUD_BLESSING, memberInfo));
                     Log.d(TAG, "JOINED the syncgroup: " + sgName);
                 } catch (SyncgroupJoinFailedException e) {
                     Log.w(TAG, "Failed join. Trying to create the syncgroup: " + sgName, e);
                     SyncgroupSpec spec = new SyncgroupSpec(
-                            "TODOs User Data Collection", permissions,
+                            "TODOs User Data Collection", CLOUD_NAME, permissions,
                             ImmutableList.of(new CollectionRow(sUserCollection.id(), "")),
                             ImmutableList.of(MOUNTPOINT), false);
                     try {
@@ -342,7 +335,7 @@
     }
 
     protected String computeListSyncgroupName(String listId) {
-        return CLOUD_NAME + LIST_COLLECTION_SYNCGROUP_SUFFIX + listId;
+        return LIST_COLLECTION_SYNCGROUP_SUFFIX + listId;
     }
 
     private static volatile boolean sInitialized;
@@ -477,7 +470,8 @@
             }
             final String timestamp = DateTimeFormat.forPattern("yyyy-MM-dd").print(new DateTime());
             try {
-                return sRemoteInspectors.invite("invited-on-"+timestamp, Duration.standardDays(1));
+                return sRemoteInspectors.invite("invited-on-" + timestamp, Duration.standardDays
+                        (1));
             } catch (VException e) {
                 return "Unable to setup remote inspection: " + e;
             }
diff --git a/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbaseTodoList.java b/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbaseTodoList.java
index 6c12a7b..f735fc4 100644
--- a/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbaseTodoList.java
+++ b/app/src/syncbase/java/io/v/todos/persistence/syncbase/SyncbaseTodoList.java
@@ -38,6 +38,7 @@
 import io.v.v23.security.access.AccessList;
 import io.v.v23.security.access.Constants;
 import io.v.v23.security.access.Permissions;
+import io.v.v23.services.syncbase.Id;
 import io.v.v23.services.syncbase.SyncgroupSpec;
 import io.v.v23.syncbase.ChangeType;
 import io.v.v23.syncbase.Collection;
@@ -204,7 +205,8 @@
     }
 
     private Syncgroup getListSyncgroup() {
-        return getDatabase().getSyncgroup(computeListSyncgroupName(mList.id().getName()));
+        return getDatabase().getSyncgroup(new Id(getPersonalBlessingsString(getVContext()),
+                computeListSyncgroupName(mList.id().getName())));
     }
 
     @Override