reader/android: DB interface similar to syncslides.

Change-Id: I0fe2842955d2e1464ecb3146962b25e1c2d18c81
diff --git a/android/app/src/main/java/io/v/android/apps/reader/DB.java b/android/app/src/main/java/io/v/android/apps/reader/DB.java
new file mode 100644
index 0000000..f6fa2a0
--- /dev/null
+++ b/android/app/src/main/java/io/v/android/apps/reader/DB.java
@@ -0,0 +1,88 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io.v.android.apps.reader;
+
+import android.content.Context;
+
+/**
+ * Borrowed the idea of having a DB interface from syncslides.
+ *
+ * Provides high-level methods for getting and setting the state of PDF reader.
+ * It is an interface instead of a concrete class to make testing easier.
+ */
+public interface DB {
+
+    class Singleton {
+
+        private static volatile DB instance;
+
+        public static DB get(Context context) {
+            DB result = instance;
+            if (instance == null) {
+                synchronized (Singleton.class) {
+                    result = instance;
+                    if (result == null) {
+                        // TODO(youngseokyoon): Replace this with a syncbase DB.
+                        instance = result = new FakeDB(context);
+                    }
+                }
+            }
+
+            return result;
+        }
+    }
+
+    /**
+     * Represents a PDF file and its metadata.
+     *
+     * TODO(youngseokyoon): update this interface, once the syncbase DB schema is defined.
+     */
+    interface PdfFile {
+        String getName();
+    }
+
+    /**
+     * Callbacks for when the dataset changes dynamically.
+     *
+     * TODO(youngseokyoon): reorganize the interfaces into sub-packages.
+     */
+    interface Listener {
+        void notifyItemChanged(int position);
+        void notifyItemInserted(int position);
+        void notifyItemRemoved(int position);
+    }
+
+    /**
+     * Provides a list of PDF files via an API that fits well with RecyclerView.Adapter.
+     */
+    interface PdfFileList {
+        /**
+         * Returns the number of available PDF files.
+         */
+        int getItemCount();
+
+        /**
+         * Returns the PDF file object at the given position.
+         */
+        PdfFile getPdfFile(int position);
+
+        /**
+         * Sets the listener for changes to the list.  There can only be one listener.
+         */
+        void setListener(Listener listener);
+
+        /**
+         * Indicates that the list is no longer needed and should stop notifying its listener.
+         */
+        void discard();
+    }
+
+    /**
+     * Gets the list of available PDF files.
+     * @return a list of PDF files.
+     */
+    PdfFileList getPdfFileList();
+
+}
diff --git a/android/app/src/main/java/io/v/android/apps/reader/FakeDB.java b/android/app/src/main/java/io/v/android/apps/reader/FakeDB.java
new file mode 100644
index 0000000..c78d431
--- /dev/null
+++ b/android/app/src/main/java/io/v/android/apps/reader/FakeDB.java
@@ -0,0 +1,83 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io.v.android.apps.reader;
+
+import android.content.Context;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A fake implementation of the DB interface for manual testing.
+ */
+public class FakeDB implements DB {
+
+    private static final String[] PDF_FILE_NAMES = {
+            "Foo.pdf",
+            "Bar.pdf"
+    };
+
+    private FakePdfFileList mPdfFileList;
+
+    public FakeDB(Context context) {
+        mPdfFileList = new FakePdfFileList();
+    }
+
+    class FakePdfFile implements DB.PdfFile {
+
+        private String mName;
+
+        public FakePdfFile(String name) {
+            mName = name;
+        }
+
+        @Override
+        public String getName() {
+            return mName;
+        }
+    }
+
+    class FakePdfFileList implements DB.PdfFileList {
+
+        private List<FakePdfFile> mPdfFiles;
+        private Listener mListener;
+
+        public FakePdfFileList() {
+            mPdfFiles = new ArrayList<>();
+            for (String fileName : PDF_FILE_NAMES) {
+                mPdfFiles.add(new FakePdfFile(fileName));
+            }
+        }
+
+        @Override
+        public int getItemCount() {
+            return mPdfFiles.size();
+        }
+
+        @Override
+        public FakePdfFile getPdfFile(int position) {
+            return mPdfFiles.get(position);
+        }
+
+        @Override
+        public void setListener(Listener listener) {
+            // This fake list never calls the notify methods.
+            // Just check if the listener is set only once.
+            assert mListener == null;
+            mListener = listener;
+        }
+
+        @Override
+        public void discard() {
+            // Nothing to do.
+        }
+    }
+
+    @Override
+    public PdfFileList getPdfFileList() {
+        return mPdfFileList;
+    }
+
+}
diff --git a/android/app/src/main/java/io/v/android/apps/reader/PdfChooserActivity.java b/android/app/src/main/java/io/v/android/apps/reader/PdfChooserActivity.java
index 4549cc7..580f494 100644
--- a/android/app/src/main/java/io/v/android/apps/reader/PdfChooserActivity.java
+++ b/android/app/src/main/java/io/v/android/apps/reader/PdfChooserActivity.java
@@ -21,22 +21,30 @@
  */
 public class PdfChooserActivity extends Activity {
 
+    private RecyclerView mRecyclerView;
+    private PdfListAdapter mAdapter;
+
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_pdf_chooser);
 
-        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.pdf_list);
-        recyclerView.setHasFixedSize(true);
+        mRecyclerView = (RecyclerView) findViewById(R.id.pdf_list);
+        mRecyclerView.setHasFixedSize(true);
 
         // Use the linear layout manager for the recycler view
         RecyclerView.LayoutManager layoutManager= new LinearLayoutManager(this);
-        recyclerView.setLayoutManager(layoutManager);
+        mRecyclerView.setLayoutManager(layoutManager);
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
 
         // The adapter for the recycler view
-        PdfListAdapter adapter = new PdfListAdapter();
+        mAdapter = new PdfListAdapter(this);
 
         // When a file is clicked from the list, start the PdfViewerActivity.
-        adapter.setOnPdfFileClickListener(new PdfListAdapter.OnPdfFileClickListener() {
+        mAdapter.setOnPdfFileClickListener(new PdfListAdapter.OnPdfFileClickListener() {
             @Override
             public void onPdfFileClick(PdfListAdapter adapter, View v, int position) {
                 Intent intent = PdfViewerActivity.createIntent(
@@ -46,7 +54,15 @@
             }
         });
 
-        recyclerView.setAdapter(adapter);
+        mRecyclerView.setAdapter(mAdapter);
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+
+        mAdapter.stop();
+        mAdapter = null;
     }
 
     @Override
diff --git a/android/app/src/main/java/io/v/android/apps/reader/PdfListAdapter.java b/android/app/src/main/java/io/v/android/apps/reader/PdfListAdapter.java
index 0a570b6..c134fcf 100644
--- a/android/app/src/main/java/io/v/android/apps/reader/PdfListAdapter.java
+++ b/android/app/src/main/java/io/v/android/apps/reader/PdfListAdapter.java
@@ -4,6 +4,7 @@
 
 package io.v.android.apps.reader;
 
+import android.content.Context;
 import android.support.v7.widget.CardView;
 import android.support.v7.widget.RecyclerView;
 import android.view.LayoutInflater;
@@ -11,18 +12,17 @@
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+import io.v.android.apps.reader.DB.Listener;
+import io.v.android.apps.reader.DB.PdfFileList;
+
 /**
  * Adapter that binds the list of pdf files to the corresponding card views.
  */
-public class PdfListAdapter extends RecyclerView.Adapter<PdfListAdapter.ViewHolder> {
+public class PdfListAdapter extends RecyclerView.Adapter<PdfListAdapter.ViewHolder>
+        implements Listener {
 
-    private OnPdfFileClickListener mListener;
-
-    // TODO(youngseokyoon): Replace this temporary list with real data coming from the syncbase.
-    private static final String[] SAMPLE_PDF_LIST = {
-            "Foo.pdf",
-            "Bar.pdf",
-    };
+    private OnPdfFileClickListener mClickListener;
+    private PdfFileList mPdfFileList;
 
     public class ViewHolder extends RecyclerView.ViewHolder {
         public CardView mCardView;
@@ -36,16 +36,20 @@
             mCardView.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
-                    if (mListener != null) {
-                        mListener.onPdfFileClick(PdfListAdapter.this, v, getPosition());
+                    if (mClickListener != null) {
+                        mClickListener.onPdfFileClick(PdfListAdapter.this, v, getPosition());
                     }
                 }
             });
         }
     }
 
-    public PdfListAdapter() {
-        mListener = null;
+    public PdfListAdapter(Context context) {
+        mClickListener = null;
+
+        DB db = DB.Singleton.get(context);
+        mPdfFileList = db.getPdfFileList();
+        mPdfFileList.setListener(this);
     }
 
     @Override
@@ -63,16 +67,21 @@
     }
 
     public String getItem(int position) {
-        return SAMPLE_PDF_LIST[position];
+        return mPdfFileList.getPdfFile(position).getName();
     }
 
     @Override
     public int getItemCount() {
-        return SAMPLE_PDF_LIST.length;
+        return mPdfFileList.getItemCount();
     }
 
-    public void setOnPdfFileClickListener(OnPdfFileClickListener listener) {
-        mListener = listener;
+    public void setOnPdfFileClickListener(OnPdfFileClickListener clickListener) {
+        mClickListener = clickListener;
+    }
+
+    public void stop() {
+        mPdfFileList.discard();
+        mPdfFileList = null;
     }
 
     /**