Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 328494b2 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Show voicemail error messages for NUI"

parents 2684d0b9 c5b58aa3
Loading
Loading
Loading
Loading
+125 −39
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.media.MediaPlayer.OnPreparedListener;
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.DialerExecutorComponent;
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 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<ViewHolder>
  }

  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 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<ViewHolder>
  /** 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 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<ViewHolder>
    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 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<ViewHolder>
        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 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<ViewHolder>
    }

    newVoicemailViewHolder.reset();
    cursor.moveToPosition(position - previousHeaders);
    cursor.moveToPosition(position - nonVoicemailEntryHeaders);
    newVoicemailViewHolder.bindViewHolderValuesFromAdapter(
        cursor, fragmentManager, mediaPlayer, position, currentlyExpandedViewHolderId);

@@ -378,6 +355,72 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<ViewHolder>
    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 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<ViewHolder>
      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);
    }
  }
}
+28 −4
Original line number Diff line number Diff line
@@ -18,19 +18,43 @@ package com.android.dialer.voicemail.listui;

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());
  }
}
+29 −0
Original line number Diff line number Diff line
@@ -28,11 +28,15 @@ import android.view.LayoutInflater;
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 @@ public final class NewVoicemailFragment extends Fragment implements LoaderCallba
      ((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
+90 −11
Original line number Diff line number Diff line
@@ -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 -->
    android:layout_height="wrap_content"
    android:orientation="vertical">

  <LinearLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      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/new_voicemail_alert_text"
      style="@style/SecondaryText"
          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:layout_marginStart="@dimen/voicemail_header_margin_start"
      android:layout_centerVertical="true"/>
</RelativeLayout>
        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>
+9 −0
Original line number Diff line number Diff line
@@ -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>