reader/android: receive implicit intent from other apps

Change-Id: I53f88df8c980ba69e05e8e46bd5b6cd59fc656a5
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 2c258f7..0c278cf 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -18,6 +18,11 @@
         <activity
             android:name=".PdfViewerActivity"
             android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.SEND" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="application/pdf" />
+            </intent-filter>
         </activity>
     </application>
 
diff --git a/android/app/src/main/java/io/v/android/apps/reader/PdfViewerActivity.java b/android/app/src/main/java/io/v/android/apps/reader/PdfViewerActivity.java
index d7deae1..95309c2 100644
--- a/android/app/src/main/java/io/v/android/apps/reader/PdfViewerActivity.java
+++ b/android/app/src/main/java/io/v/android/apps/reader/PdfViewerActivity.java
@@ -98,6 +98,14 @@
     protected void onStart() {
         super.onStart();
 
+        /**
+         * Suppress the start process until the DB initialization is completed.
+         * onStart() method will be called again after the user selects her blessings.
+         */
+        if (!mDB.isInitialized()) {
+            return;
+        }
+
         mDeviceSets = mDB.getDeviceSetList();
         mDeviceSets.setListener(new Listener() {
             @Override
@@ -134,6 +142,7 @@
              * The EXTRA_DEVICE_SET_ID value is set when this activity is started by touching one of
              * the existing device sets from the DeviceSetChooserActivity.
              */
+            Log.i(TAG, "onStart: Case #1: started by selecting an existing device set.");
 
             // Get the device set from the DB and join it.
             DeviceSet ds = mDeviceSets.getItemById(intent.getStringExtra(EXTRA_DEVICE_SET_ID));
@@ -145,26 +154,43 @@
              * the floating action button from the DeviceSetChooserActivity and selecting one of the
              * local PDF files from the browser.
              */
-            // Get the file content.
-            java.io.File jFile = getFileFromUri(intent.getData());
-            if (jFile == null) {
-                Log.e(TAG, "Could not get the file content of Uri: " + intent.getData().toString());
-                return;
-            }
+            Log.i(TAG, "onStart: Case #2: started by using the floating action button.");
 
-            // Create a vdl File object representing this pdf file and put it in the db.
-            File vFile = createVdlFile(jFile, intent.getData());
-            mDB.addFile(vFile);
+            Uri uri = intent.getData();
+            createAndJoinDeviceSet(uri);
+        } else if (intent.hasExtra(Intent.EXTRA_STREAM)) {
+            /**
+             * Case #3.
+             * The EXTRA_STREAM value is set when this activity is started by receiving an implicit
+             * intent from another app by sharing a PDF file to the reader app.
+             */
+            Log.i(TAG, "onStart: Case #3: started by an implicit intent from another app.");
 
-            // Create a device set object and put it in the db.
-            DeviceSet ds = createDeviceSet(vFile);
-            mDB.addDeviceSet(ds);
-
-            // Join the device set.
-            joinDeviceSet(ds);
+            Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
+            createAndJoinDeviceSet(uri);
         }
     }
 
+    private void createAndJoinDeviceSet(Uri fileUri) {
+        // Get the file content.
+        java.io.File jFile = getFileFromUri(fileUri);
+        if (jFile == null) {
+            Log.e(TAG, "Could not get the file content of Uri: " + fileUri.toString());
+            return;
+        }
+
+        // Create a vdl File object representing this pdf file and put it in the db.
+        File vFile = createVdlFile(jFile, fileUri);
+        mDB.addFile(vFile);
+
+        // Create a device set object and put it in the db.
+        DeviceSet ds = createDeviceSet(vFile);
+        mDB.addDeviceSet(ds);
+
+        // Join the device set.
+        joinDeviceSet(ds);
+    }
+
     @Override
     protected void onStop() {
         super.onStop();
@@ -423,4 +449,19 @@
         Log.e(TAG, e.getMessage(), e);
     }
 
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+
+        Log.i(TAG, String.format("onActivityResult(%d, %d, data) called", requestCode, resultCode));
+        if (mDB.onActivityResult(requestCode, resultCode, data)) {
+            return;
+        }
+
+        // Any other activity results would be handled here.
+        Log.w(TAG, String.format(
+                "Unhandled activity result. (requestCode: %d, resultCode: %d)",
+                requestCode, resultCode));
+    }
+
 }
diff --git a/android/app/src/main/java/io/v/android/apps/reader/db/DB.java b/android/app/src/main/java/io/v/android/apps/reader/db/DB.java
index eec476b..703f0bc 100644
--- a/android/app/src/main/java/io/v/android/apps/reader/db/DB.java
+++ b/android/app/src/main/java/io/v/android/apps/reader/db/DB.java
@@ -50,6 +50,13 @@
     void init(Activity activity);
 
     /**
+     * Tells if initialization process is completed.
+     *
+     * @return true if the initialization process is completed.
+     */
+    boolean isInitialized();
+
+    /**
      * If init() sent an intent to another Activity, the result must be forwarded
      * from our app's activity to this method.
      *
diff --git a/android/app/src/main/java/io/v/android/apps/reader/db/FakeDB.java b/android/app/src/main/java/io/v/android/apps/reader/db/FakeDB.java
index f190d10..e9a9443 100644
--- a/android/app/src/main/java/io/v/android/apps/reader/db/FakeDB.java
+++ b/android/app/src/main/java/io/v/android/apps/reader/db/FakeDB.java
@@ -132,11 +132,17 @@
         }
     }
 
+    @Override
     public void init(Activity activity) {
         // Nothing to do.
     }
 
     @Override
+    public boolean isInitialized() {
+        return true;
+    }
+
+    @Override
     public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
         // Nothing to do.
         return false;
diff --git a/android/app/src/main/java/io/v/android/apps/reader/db/SyncbaseDB.java b/android/app/src/main/java/io/v/android/apps/reader/db/SyncbaseDB.java
index f040dfb..7c6d78e 100644
--- a/android/app/src/main/java/io/v/android/apps/reader/db/SyncbaseDB.java
+++ b/android/app/src/main/java/io/v/android/apps/reader/db/SyncbaseDB.java
@@ -97,17 +97,19 @@
 
     @Override
     public void init(Activity activity) {
-        if (mVContext != null) {
+        if (isInitialized()) {
             // Already initialized.
             return;
         }
 
-        mVContext = V.init(mContext);
-        try {
-            mVContext = V.withListenSpec(
-                    mVContext, V.getListenSpec(mVContext).withProxy("proxy"));
-        } catch (VException e) {
-            handleError("Couldn't setup vanadium proxy: " + e.getMessage());
+        if (mVContext == null) {
+            mVContext = V.init(mContext);
+            try {
+                mVContext = V.withListenSpec(
+                        mVContext, V.getListenSpec(mVContext).withProxy("proxy"));
+            } catch (VException e) {
+                handleError("Couldn't setup vanadium proxy: " + e.getMessage());
+            }
         }
 
         AccessList acl = new AccessList(
@@ -121,6 +123,11 @@
         getBlessings(activity);
     }
 
+    @Override
+    public boolean isInitialized() {
+        return mInitialized;
+    }
+
     private void getBlessings(Activity activity) {
         Blessings blessings = null;
         try {