Merge "Show voicemail error messages for NUI"
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
index 5519aa4..318f797 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
@@ -25,6 +25,7 @@
 import android.net.Uri;
 import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
 import android.support.annotation.WorkerThread;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.ViewHolder;
@@ -43,9 +44,15 @@
 import com.android.dialer.common.concurrent.ThreadUtil;
 import com.android.dialer.time.Clock;
 import com.android.dialer.voicemail.listui.NewVoicemailViewHolder.NewVoicemailViewHolderListener;
+import com.android.dialer.voicemail.listui.error.VoicemailErrorMessage;
+import com.android.dialer.voicemail.listui.error.VoicemailErrorMessageCreator;
+import com.android.dialer.voicemail.listui.error.VoicemailStatus;
 import com.android.dialer.voicemail.model.VoicemailEntry;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
 import java.util.Objects;
 import java.util.Set;
 
@@ -66,6 +73,7 @@
   }
 
   private Cursor cursor;
+  private Cursor voicemailStatusCursor;
   private final Clock clock;
 
   /** {@link Integer#MAX_VALUE} when the "Today" header should not be displayed. */
@@ -81,6 +89,8 @@
   /** A valid id for {@link VoicemailEntry} is greater than 0 */
   private int currentlyExpandedViewHolderId = -1;
 
+  private VoicemailErrorMessage voicemailErrorMessage;
+
   /**
    * It takes time to delete voicemails from the server, so we "remove" them and remember the
    * positions we removed until a new cursor is ready.
@@ -248,34 +258,14 @@
     if (viewHolder instanceof NewVoicemailHeaderViewHolder) {
       LogUtil.i(
           "NewVoicemailAdapter.onBindViewHolder", "view holder at pos:%d is a header", position);
-      NewVoicemailHeaderViewHolder headerViewHolder = (NewVoicemailHeaderViewHolder) viewHolder;
-      @RowType int viewType = getItemViewType(position);
-      if (position == todayHeaderPosition) {
-        headerViewHolder.setHeader(R.string.new_voicemail_header_today);
-      } else if (position == yesterdayHeaderPosition) {
-        headerViewHolder.setHeader(R.string.new_voicemail_header_yesterday);
-      } else if (position == olderHeaderPosition) {
-        headerViewHolder.setHeader(R.string.new_voicemail_header_older);
-      } else {
-        throw Assert.createIllegalStateFailException(
-            "Unexpected view type " + viewType + " at position: " + position);
-      }
+      onBindHeaderViewHolder(viewHolder, position);
       return;
     }
 
     if (viewHolder instanceof NewVoicemailAlertViewHolder) {
       LogUtil.i(
           "NewVoicemailAdapter.onBindViewHolder", "view holder at pos:%d is a alert", position);
-      NewVoicemailAlertViewHolder alertViewHolder = (NewVoicemailAlertViewHolder) viewHolder;
-      @RowType int viewType = getItemViewType(position);
-      Assert.checkArgument(position == 0);
-      if (position == voicemailAlertPosition) {
-        // TODO(a bug): Update this with the alert messages
-        alertViewHolder.setHeader("Temporary placeholder, update this with the alert messages");
-      } else {
-        throw Assert.createIllegalStateFailException(
-            "Unexpected view type " + viewType + " at position: " + position);
-      }
+      onBindAlertViewHolder(viewHolder, position);
       return;
     }
 
@@ -285,26 +275,13 @@
         position);
 
     NewVoicemailViewHolder newVoicemailViewHolder = (NewVoicemailViewHolder) viewHolder;
-
-    int previousHeaders = 0;
-    if (voicemailAlertPosition != Integer.MAX_VALUE && position > voicemailAlertPosition) {
-      previousHeaders++;
-    }
-    if (todayHeaderPosition != Integer.MAX_VALUE && position > todayHeaderPosition) {
-      previousHeaders++;
-    }
-    if (yesterdayHeaderPosition != Integer.MAX_VALUE && position > yesterdayHeaderPosition) {
-      previousHeaders++;
-    }
-    if (olderHeaderPosition != Integer.MAX_VALUE && position > olderHeaderPosition) {
-      previousHeaders++;
-    }
+    int nonVoicemailEntryHeaders = getHeaderCountAtPosition(position);
 
     LogUtil.i(
         "NewVoicemailAdapter.onBindViewHolder",
-        "view holder at pos:%d, prevHeaderCount:%d",
+        "view holder at pos:%d, nonVoicemailEntryHeaders:%d",
         position,
-        previousHeaders);
+        nonVoicemailEntryHeaders);
 
     // Remove if the viewholder is being recycled.
     if (newVoicemailViewHolderArrayMap.containsKey(newVoicemailViewHolder.getViewHolderId())) {
@@ -322,7 +299,7 @@
     }
 
     newVoicemailViewHolder.reset();
-    cursor.moveToPosition(position - previousHeaders);
+    cursor.moveToPosition(position - nonVoicemailEntryHeaders);
     newVoicemailViewHolder.bindViewHolderValuesFromAdapter(
         cursor, fragmentManager, mediaPlayer, position, currentlyExpandedViewHolderId);
 
@@ -378,6 +355,72 @@
     printArrayMap();
   }
 
+  private int getHeaderCountAtPosition(int position) {
+    int previousHeaders = 0;
+    if (voicemailAlertPosition != Integer.MAX_VALUE && position > voicemailAlertPosition) {
+      previousHeaders++;
+    }
+    if (todayHeaderPosition != Integer.MAX_VALUE && position > todayHeaderPosition) {
+      previousHeaders++;
+    }
+    if (yesterdayHeaderPosition != Integer.MAX_VALUE && position > yesterdayHeaderPosition) {
+      previousHeaders++;
+    }
+    if (olderHeaderPosition != Integer.MAX_VALUE && position > olderHeaderPosition) {
+      previousHeaders++;
+    }
+    return previousHeaders;
+  }
+
+  private void onBindAlertViewHolder(ViewHolder viewHolder, int position) {
+    LogUtil.i(
+        "NewVoicemailAdapter.onBindAlertViewHolder",
+        "pos:%d, voicemailAlertPosition:%d",
+        position,
+        voicemailAlertPosition);
+
+    NewVoicemailAlertViewHolder alertViewHolder = (NewVoicemailAlertViewHolder) viewHolder;
+    @RowType int viewType = getItemViewType(position);
+
+    Assert.checkArgument(position == 0, "position is not 0");
+    Assert.checkArgument(
+        position == voicemailAlertPosition,
+        String.format(
+            Locale.US,
+            "position:%d and voicemailAlertPosition:%d are different",
+            position,
+            voicemailAlertPosition));
+    Assert.checkArgument(viewType == RowType.VOICEMAIL_ALERT, "Invalid row type: " + viewType);
+    Assert.checkArgument(
+        voicemailErrorMessage.getActions().size() <= 2,
+        "Too many actions: " + voicemailErrorMessage.getActions().size());
+
+    alertViewHolder.setTitle(voicemailErrorMessage.getTitle());
+    alertViewHolder.setDescription(voicemailErrorMessage.getDescription());
+
+    if (!voicemailErrorMessage.getActions().isEmpty()) {
+      alertViewHolder.setPrimaryButton(voicemailErrorMessage.getActions().get(0));
+    }
+    if (voicemailErrorMessage.getActions().size() > 1) {
+      alertViewHolder.setSecondaryButton(voicemailErrorMessage.getActions().get(1));
+    }
+  }
+
+  private void onBindHeaderViewHolder(ViewHolder viewHolder, int position) {
+    NewVoicemailHeaderViewHolder headerViewHolder = (NewVoicemailHeaderViewHolder) viewHolder;
+    @RowType int viewType = getItemViewType(position);
+    if (position == todayHeaderPosition) {
+      headerViewHolder.setHeader(R.string.new_voicemail_header_today);
+    } else if (position == yesterdayHeaderPosition) {
+      headerViewHolder.setHeader(R.string.new_voicemail_header_yesterday);
+    } else if (position == olderHeaderPosition) {
+      headerViewHolder.setHeader(R.string.new_voicemail_header_older);
+    } else {
+      throw Assert.createIllegalStateFailException(
+          "Unexpected view type " + viewType + " at position: " + position);
+    }
+  }
+
   private void printArrayMap() {
     LogUtil.i(
         "NewVoicemailAdapter.printArrayMap",
@@ -958,4 +1001,47 @@
       LogUtil.i("NewVoicemailAdapter.checkAndPlayVoicemail", "not playing downloaded voicemail");
     }
   }
+
+  @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+  public void setVoicemailStatusCursor(Cursor voicemailStatusCursor) {
+    this.voicemailStatusCursor = voicemailStatusCursor;
+  }
+
+  // TODO(uabdullah): Handle ToS properly
+  public void updateAlert(Context context) {
+    if (voicemailStatusCursor == null) {
+      LogUtil.i("NewVoicemailAdapter.updateAlert", "status cursor was null");
+      return;
+    }
+
+    LogUtil.i(
+        "NewVoicemailAdapter.updateAlert",
+        "status cursor size was " + voicemailStatusCursor.getCount());
+
+    List<VoicemailStatus> statuses = new ArrayList<>();
+
+    while (voicemailStatusCursor.moveToNext()) {
+      VoicemailStatus status = new VoicemailStatus(context, voicemailStatusCursor);
+      if (status.isActive()) {
+        statuses.add(status);
+        // TODO(uabdullah): addServiceStateListener
+      }
+    }
+
+    voicemailErrorMessage = null;
+    VoicemailErrorMessageCreator messageCreator = new VoicemailErrorMessageCreator();
+
+    for (VoicemailStatus status : statuses) {
+      voicemailErrorMessage = messageCreator.create(context, status, null);
+      if (voicemailErrorMessage != null) {
+        break;
+      }
+    }
+
+    if (voicemailErrorMessage != null) {
+      voicemailAlertPosition = 0;
+      updateHeaderPositions();
+      notifyItemChanged(0);
+    }
+  }
 }
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailAlertViewHolder.java b/java/com/android/dialer/voicemail/listui/NewVoicemailAlertViewHolder.java
index ec603b5..ac989a8 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailAlertViewHolder.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailAlertViewHolder.java
@@ -18,19 +18,43 @@
 
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.view.View;
+import android.widget.Button;
 import android.widget.TextView;
+import com.android.dialer.voicemail.listui.error.VoicemailErrorMessage.Action;
 
 /** ViewHolder for {@link NewVoicemailAdapter} to display voicemail error states. */
 final class NewVoicemailAlertViewHolder extends ViewHolder {
 
-  private final TextView errorTextView;
+  private final TextView voicemailErrorTitleTextView;
+  private final TextView voicemailErrorDetailsTextView;
+  private final Button primaryButton;
+  private final Button secondaryButton;
 
   NewVoicemailAlertViewHolder(View view) {
     super(view);
-    errorTextView = view.findViewById(R.id.new_voicemail_alert_text);
+    voicemailErrorTitleTextView = view.findViewById(R.id.voicemail_alert_header);
+    voicemailErrorDetailsTextView = view.findViewById(R.id.voicemail_alert_details);
+    primaryButton = view.findViewById(R.id.voicemail_alert_primary_button);
+    secondaryButton = view.findViewById(R.id.voicemail_alert_primary_button);
   }
 
-  void setHeader(String error) {
-    errorTextView.setText(error);
+  void setTitle(CharSequence error) {
+    voicemailErrorTitleTextView.setText(error);
+  }
+
+  void setDescription(CharSequence error) {
+    voicemailErrorDetailsTextView.setText(error);
+  }
+
+  void setPrimaryButton(Action action) {
+    primaryButton.setVisibility(View.VISIBLE);
+    primaryButton.setText(action.getText());
+    primaryButton.setOnClickListener(action.getListener());
+  }
+
+  void setSecondaryButton(Action action) {
+    secondaryButton.setVisibility(View.VISIBLE);
+    secondaryButton.setText(action.getText());
+    secondaryButton.setOnClickListener(action.getListener());
   }
 }
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java
index b4be424..0d91f01 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java
@@ -28,11 +28,15 @@
 import android.view.View;
 import android.view.ViewGroup;
 import com.android.dialer.common.LogUtil;
+import com.android.dialer.database.CallLogQueryHandler;
+import com.android.dialer.database.CallLogQueryHandler.Listener;
 
+// TODO(uabdullah): Register content observer for VoicemailContract.Status.CONTENT_URI in onStart
 /** Fragment for Dialer Voicemail Tab. */
 public final class NewVoicemailFragment extends Fragment implements LoaderCallbacks<Cursor> {
 
   private RecyclerView recyclerView;
+  private CallLogQueryHandler callLogQueryHandler;
 
   @Nullable
   @Override
@@ -72,6 +76,31 @@
       ((NewVoicemailAdapter) recyclerView.getAdapter()).updateCursor(data);
       ((NewVoicemailAdapter) recyclerView.getAdapter()).checkAndPlayVoicemail();
     }
+    callLogQueryHandler =
+        new CallLogQueryHandler(
+            getContext(), getContext().getContentResolver(), new NewVoicemailFragmentListener());
+    callLogQueryHandler.fetchVoicemailStatus();
+  }
+
+  private final class NewVoicemailFragmentListener implements Listener {
+
+    @Override
+    public void onVoicemailStatusFetched(Cursor statusCursor) {
+      LogUtil.enterBlock("NewVoicemailFragmentListener.onVoicemailStatusFetched");
+      ((NewVoicemailAdapter) recyclerView.getAdapter()).setVoicemailStatusCursor(statusCursor);
+      ((NewVoicemailAdapter) recyclerView.getAdapter()).updateAlert(getContext());
+    }
+
+    @Override
+    public void onVoicemailUnreadCountFetched(Cursor cursor) {}
+
+    @Override
+    public void onMissedCallsUnreadCountFetched(Cursor cursor) {}
+
+    @Override
+    public boolean onCallsFetched(Cursor combinedCursor) {
+      return false;
+    }
   }
 
   @Override
diff --git a/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_entry_alert.xml b/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_entry_alert.xml
index e8dcd02..28d6391 100644
--- a/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_entry_alert.xml
+++ b/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_entry_alert.xml
@@ -14,17 +14,96 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<RelativeLayout
+
+<!-- TODO(uabdullah): Use a relative layout instead of nested linear layouts.-->
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="48dp"
+    android:id="@+id/voicemail_alert_content"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content">
-  <!-- TODO(uabdullah): Confirm with UX on mocks -->
-  <TextView
-      android:id="@+id/new_voicemail_alert_text"
-      style="@style/SecondaryText"
-      android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+  <LinearLayout
+      android:layout_width="match_parent"
       android:layout_height="wrap_content"
-      android:layout_marginStart="@dimen/voicemail_header_margin_start"
-      android:layout_centerVertical="true"/>
-</RelativeLayout>
+      android:paddingTop="@dimen/alert_main_padding"
+      android:paddingBottom="@dimen/alert_main_padding"
+      android:paddingStart="@dimen/alert_main_padding"
+      android:paddingEnd="@dimen/alert_main_padding"
+      android:gravity="top"
+      android:orientation="horizontal">
+
+    <ImageView
+        android:id="@+id/voicemail_alert_icon"
+        android:layout_width="@dimen/voicemail_promo_card_icon_size"
+        android:layout_height="@dimen/voicemail_promo_card_icon_size"
+        android:layout_gravity="top"
+        android:src="@drawable/ic_voicemail_error_24px"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/voicemail_promo_card_main_padding"
+        android:gravity="center_vertical"
+        android:orientation="vertical">
+
+      <TextView
+          android:id="@+id/voicemail_alert_header"
+          android:textStyle="bold"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:layout_marginBottom="@dimen/voicemail_promo_card_title_padding"
+          android:layout_gravity="center_vertical"
+          android:singleLine="false"
+          android:text="Voicemail Alert"
+          android:textSize="@dimen/voicemail_promo_card_title_text_size"/>
+
+      <TextView
+          android:id="@+id/voicemail_alert_details"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:lineSpacingExtra="@dimen/voicemail_promo_card_line_spacing"
+          android:singleLine="false"
+          android:text="This is a voicemail alert message."
+          android:textSize="@dimen/voicemail_promo_card_message_size"/>
+    </LinearLayout>
+  </LinearLayout>
+
+  <LinearLayout
+      android:id="@+id/voicemail_alert_button"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:layout_gravity="end"
+      android:paddingTop="10dp"
+      android:paddingBottom="10dp"
+      android:paddingStart="16dp"
+      android:paddingEnd="16dp"
+      android:gravity="end"
+      android:minHeight="56dp"
+      android:orientation="horizontal">
+    <Button
+        android:id="@+id/voicemail_alert_secondary_button"
+        style="@style/TosButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textColor="@color/dialer_theme_color"/>
+
+    <Button
+        android:id="@+id/voicemail_alert_primary_button"
+        style="@style/TosButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textColor="@color/dialer_theme_color"/>
+  </LinearLayout>
+
+  <LinearLayout
+      android:layout_width="0dip"
+      android:layout_height="match_parent"
+      android:layout_weight="1"
+      android:layout_gravity="center"
+      android:divider="?android:dividerHorizontal"
+      android:gravity="center"
+      android:orientation="vertical"
+      android:showDividers="middle">
+  </LinearLayout>
+</LinearLayout>
diff --git a/java/com/android/dialer/voicemail/listui/res/values/dimens.xml b/java/com/android/dialer/voicemail/listui/res/values/dimens.xml
index 59da7f2..960d327 100644
--- a/java/com/android/dialer/voicemail/listui/res/values/dimens.xml
+++ b/java/com/android/dialer/voicemail/listui/res/values/dimens.xml
@@ -41,4 +41,13 @@
 
   <dimen name="voicemail_tos_image_size">280dp</dimen>
 
+  <!-- Dimensions for voicemail alert -->
+  <dimen name="alert_main_padding">24dp</dimen>
+  <dimen name="voicemail_promo_card_icon_size">24dp</dimen>
+  <dimen name="voicemail_promo_card_main_padding">24dp</dimen>
+  <dimen name="voicemail_promo_card_title_padding">12dp</dimen>
+  <dimen name="voicemail_promo_card_title_text_size">16sp</dimen>
+  <dimen name="voicemail_promo_card_line_spacing">4dp</dimen>
+  <dimen name="voicemail_promo_card_message_size">14sp</dimen>
+
 </resources>