Merge "Made voicemail status query from calllogfragment asynchronous."
diff --git a/res/layout/call_log_voicemail_status.xml b/res/layout/call_log_voicemail_status.xml
index 1abe998..fee2210 100644
--- a/res/layout/call_log_voicemail_status.xml
+++ b/res/layout/call_log_voicemail_status.xml
@@ -20,7 +20,8 @@
     android:layout_alignParentLeft="true"
     android:layout_alignParentBottom="true"
     android:background="?attr/call_log_voicemail_status_background_color"
-    android:baselineAligned="false">
+    android:baselineAligned="false"
+    android:visibility="gone">
     <TextView
         android:id="@+id/voicemail_status_message"
         android:layout_width="wrap_content"
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index 84a7dbf..1b5fcb2 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -331,7 +331,7 @@
         @Override
         protected void onContentChanged() {
             // Start async requery
-            startQuery();
+            startCallsQuery();
         }
 
         void setLoading(boolean loading) {
@@ -884,10 +884,20 @@
         }
     }
 
+    /**
+     * Called by {@link CallLogQueryHandler} after a successful query to voicemail status provider.
+     */
+    public void onVoicemailStatusFetched(Cursor statusCursor) {
+        if (getActivity() == null || getActivity().isFinishing()) {
+            return;
+        }
+        updateVoicemailStatusMessage(statusCursor);
+    }
+
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
         View view = inflater.inflate(R.layout.call_log_fragment, container, false);
-        mVoicemailStatusHelper = new VoicemailStatusHelperImpl(getActivity().getContentResolver());
+        mVoicemailStatusHelper = new VoicemailStatusHelperImpl();
         mStatusMessageView = view.findViewById(R.id.voicemail_status);
         mStatusMessageText = (TextView) view.findViewById(R.id.voicemail_status_message);
         mStatusMessageAction = (TextView) view.findViewById(R.id.voicemail_status_action);
@@ -915,17 +925,16 @@
             mAdapter.invalidateCache();
         }
 
-        startQuery();
+        startCallsQuery();
         resetNewCallsFlag();
-        updateVoicemailStatusMessage();
+        startVoicemailStatusQuery();
         super.onResume();
 
         mAdapter.mPreDrawListener = null; // Let it restart the thread after next draw
     }
 
-    private void updateVoicemailStatusMessage() {
-        // TODO: make call to mVoicemailStatusHelper asynchronously.
-        List<StatusMessage> messages = mVoicemailStatusHelper.getStatusMessages();
+    private void updateVoicemailStatusMessage(Cursor statusCursor) {
+        List<StatusMessage> messages = mVoicemailStatusHelper.getStatusMessages(statusCursor);
         if (messages.size() == 0) {
             mStatusMessageView.setVisibility(View.GONE);
         } else {
@@ -997,11 +1006,15 @@
         mCallLogQueryHandler.updateMissedCalls();
     }
 
-    private void startQuery() {
+    private void startCallsQuery() {
         mAdapter.setLoading(true);
         mCallLogQueryHandler.fetchCalls();
     }
 
+    private void startVoicemailStatusQuery() {
+        mCallLogQueryHandler.fetchVoicemailStatus();
+    }
+
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
diff --git a/src/com/android/contacts/calllog/CallLogQueryHandler.java b/src/com/android/contacts/calllog/CallLogQueryHandler.java
index 977c84a..a56f778 100644
--- a/src/com/android/contacts/calllog/CallLogQueryHandler.java
+++ b/src/com/android/contacts/calllog/CallLogQueryHandler.java
@@ -32,6 +32,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.provider.CallLog.Calls;
+import android.provider.VoicemailContract.Status;
 import android.util.Log;
 
 import java.lang.ref.WeakReference;
@@ -49,6 +50,9 @@
     /** The token for the query to mark all missed calls as old after seeing the call log. */
     private static final int UPDATE_MISSED_CALLS_TOKEN = 55;
 
+    /** The token for the query to fetch voicemail status messages. */
+    private static final int QUERY_VOICEMAIL_STATUS_TOKEN = 56;
+
     private final WeakReference<CallLogFragment> mFragment;
 
     /** The cursor containing the new calls, or null if they have not yet been fetched. */
@@ -131,6 +135,11 @@
         fetchOldCalls();
     }
 
+    public void fetchVoicemailStatus() {
+        startQuery(QUERY_VOICEMAIL_STATUS_TOKEN, null, Status.CONTENT_URI,
+                VoicemailStatusHelperImpl.PROJECTION, null, null, null);
+    }
+
     /** Fetches the list of new calls in the call log. */
     private void fetchNewCalls() {
         fetchCalls(QUERY_NEW_CALLS_TOKEN, true);
@@ -204,6 +213,9 @@
             // Store the returned cursor.
             mOldCallsCursor = new ExtendedCursor(
                     cursor, CallLogQuery.SECTION_NAME, CallLogQuery.SECTION_OLD_ITEM);
+        } else if (token == QUERY_VOICEMAIL_STATUS_TOKEN) {
+            updateVoicemailStatus(cursor);
+            return;
         } else {
             Log.w(TAG, "Unknown query completed: ignoring: " + token);
             return;
@@ -253,4 +265,11 @@
             fragment.onCallsFetched(combinedCursor);
         }
     }
-}
+
+    private void updateVoicemailStatus(Cursor statusCursor) {
+        final CallLogFragment fragment = mFragment.get();
+        if (fragment != null) {
+            fragment.onVoicemailStatusFetched(statusCursor);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/calllog/VoicemailStatusHelper.java b/src/com/android/contacts/calllog/VoicemailStatusHelper.java
index 607d31a..910a4f7 100644
--- a/src/com/android/contacts/calllog/VoicemailStatusHelper.java
+++ b/src/com/android/contacts/calllog/VoicemailStatusHelper.java
@@ -16,7 +16,9 @@
 
 package com.android.contacts.calllog;
 
+import android.database.Cursor;
 import android.net.Uri;
+import android.provider.VoicemailContract.Status;
 
 import java.util.List;
 
@@ -51,6 +53,10 @@
     /**
      * Returns a list of messages, in the order or priority that should be shown to the user. An
      * empty list is returned if no message needs to be shown.
+     * @param cursor The cursor pointing to the query on {@link Status#CONTENT_URI}. The projection
+     *      to be used is defined by the implementation class of this interface.
+     *      The class takes over the ownership of the cursor and closes it after processing the
+     *      request.
      */
-    public List<StatusMessage> getStatusMessages();
+    public List<StatusMessage> getStatusMessages(Cursor cursor);
 }
diff --git a/src/com/android/contacts/calllog/VoicemailStatusHelperImpl.java b/src/com/android/contacts/calllog/VoicemailStatusHelperImpl.java
index 690f102..6296542 100644
--- a/src/com/android/contacts/calllog/VoicemailStatusHelperImpl.java
+++ b/src/com/android/contacts/calllog/VoicemailStatusHelperImpl.java
@@ -27,7 +27,6 @@
 import com.android.common.io.MoreCloseables;
 import com.android.contacts.R;
 
-import android.content.ContentResolver;
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.VoicemailContract.Status;
@@ -46,7 +45,8 @@
     private static final int SETTINGS_URI_INDEX = 4;
     private static final int VOICEMAIL_ACCESS_URI_INDEX = 5;
     private static final int NUM_COLUMNS = 6;
-    private static final String[] PROJECTION = new String[NUM_COLUMNS];
+    /** Projection on the voicemail_status table used by this class. */
+    protected static final String[] PROJECTION = new String[NUM_COLUMNS];
     static {
         PROJECTION[SOURCE_PACKAGE_INDEX] = Status.SOURCE_PACKAGE;
         PROJECTION[CONFIGURATION_STATE_INDEX] = Status.CONFIGURATION_STATE;
@@ -127,12 +127,6 @@
         }
     }
 
-    private final ContentResolver mContentResolver;
-
-    public VoicemailStatusHelperImpl(ContentResolver contentResolver) {
-        mContentResolver = contentResolver;
-    }
-
     /** A wrapper on {@link StatusMessage} which additionally stores the priority of the message. */
     private static class MessageStatusWithPriority {
         private final StatusMessage mMessage;
@@ -145,12 +139,10 @@
     }
 
     @Override
-    public List<StatusMessage> getStatusMessages() {
-        Cursor cursor = null;
+    public List<StatusMessage> getStatusMessages(Cursor cursor) {
         try {
-            cursor = mContentResolver.query(Status.CONTENT_URI, PROJECTION, null, null, null);
             List<MessageStatusWithPriority> messages =
-                    new ArrayList<VoicemailStatusHelperImpl.MessageStatusWithPriority>();
+                new ArrayList<VoicemailStatusHelperImpl.MessageStatusWithPriority>();
             while(cursor.moveToNext()) {
                 MessageStatusWithPriority message = getMessageForStatusEntry(cursor);
                 if (message != null) {
diff --git a/tests/src/com/android/contacts/calllog/VoicemailStatusHelperImplTest.java b/tests/src/com/android/contacts/calllog/VoicemailStatusHelperImplTest.java
index c6bff13..0501a9a 100644
--- a/tests/src/com/android/contacts/calllog/VoicemailStatusHelperImplTest.java
+++ b/tests/src/com/android/contacts/calllog/VoicemailStatusHelperImplTest.java
@@ -32,6 +32,7 @@
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
+import android.database.Cursor;
 import android.net.Uri;
 import android.provider.VoicemailContract.Status;
 import android.test.AndroidTestCase;
@@ -71,7 +72,7 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mStatusHelper = new VoicemailStatusHelperImpl(getContentResolver());
+        mStatusHelper = new VoicemailStatusHelperImpl();
     }
 
     @Override
@@ -87,14 +88,15 @@
         super.tearDown();
     }
 
+
     public void testNoStatusEntries() {
-        assertEquals(0, mStatusHelper.getStatusMessages().size());
+        assertEquals(0, getStatusMessages().size());
     }
 
     public void testAllOK() {
         insertEntryForPackage(TEST_PACKAGE_1, getAllOkStatusValues());
         insertEntryForPackage(TEST_PACKAGE_2, getAllOkStatusValues());
-        assertEquals(0, mStatusHelper.getStatusMessages().size());
+        assertEquals(0, getStatusMessages().size());
     }
 
     public void testNotAllOKForOnePackage() {
@@ -167,7 +169,7 @@
         // package2 with  valuesNoNotificationNoDataChannel. Package2 should be above.
         updateEntryForPackage(TEST_PACKAGE_1, valuesNoNotificationGoodDataChannel);
         updateEntryForPackage(TEST_PACKAGE_2, valuesNoNotificationNoDataChannel);
-        List<StatusMessage> messages = mStatusHelper.getStatusMessages();
+        List<StatusMessage> messages = getStatusMessages();
         assertEquals(2, messages.size());
         assertEquals(TEST_PACKAGE_1, messages.get(1).sourcePackage);
         assertEquals(TEST_PACKAGE_2, messages.get(0).sourcePackage);
@@ -175,7 +177,7 @@
         // Now reverse the values - ordering should be reversed as well.
         updateEntryForPackage(TEST_PACKAGE_1, valuesNoNotificationNoDataChannel);
         updateEntryForPackage(TEST_PACKAGE_2, valuesNoNotificationGoodDataChannel);
-        messages = mStatusHelper.getStatusMessages();
+        messages = getStatusMessages();
         assertEquals(2, messages.size());
         assertEquals(TEST_PACKAGE_1, messages.get(0).sourcePackage);
         assertEquals(TEST_PACKAGE_2, messages.get(1).sourcePackage);
@@ -190,7 +192,7 @@
 
     private void checkExpectedMessage(String sourcePackage, ContentValues values,
             int expectedStatusMsg, int expectedActionMsg, Uri expectedUri) {
-        List<StatusMessage> messages = mStatusHelper.getStatusMessages();
+        List<StatusMessage> messages = getStatusMessages();
         assertEquals(1, messages.size());
         checkMessageMatches(messages.get(0), sourcePackage, expectedStatusMsg, expectedActionMsg,
                 expectedUri);
@@ -210,7 +212,7 @@
 
     private void checkNoMessages(String sourcePackage, ContentValues values) {
         assertEquals(1, updateEntryForPackage(sourcePackage, values));
-        List<StatusMessage> messages = mStatusHelper.getStatusMessages();
+        List<StatusMessage> messages = getStatusMessages();
         assertEquals(0, messages.size());
     }
 
@@ -241,6 +243,12 @@
                 Status.buildSourceUri(sourcePackage), values, null, null);
     }
 
+    private List<StatusMessage> getStatusMessages() {
+        Cursor cursor = getContentResolver().query(Status.CONTENT_URI,
+                VoicemailStatusHelperImpl.PROJECTION, null, null, null);
+        return mStatusHelper.getStatusMessages(cursor);
+    }
+
     private ContentResolver getContentResolver() {
         return getContext().getContentResolver();
     }