From c5b58aa372390b544668c79550c70237399c8c0d Mon Sep 17 00:00:00 2001 From: uabdullah Date: Thu, 25 Jan 2018 15:25:50 -0800 Subject: Show voicemail error messages for NUI This CL shows the voicemail error messages for both VVM and OMTP type voicemails. It hooks upto the existing error framework and retrieves the voicemail error states and then displays it. Bug: 71700117 Test: Unit Tests PiperOrigin-RevId: 183301455 Change-Id: Ib2b7fb957fbfd2af2227747d327cef466259eb6f --- .../voicemail/listui/NewVoicemailAdapter.java | 164 ++++++++++++++++----- .../listui/NewVoicemailAlertViewHolder.java | 32 +++- .../voicemail/listui/NewVoicemailFragment.java | 29 ++++ .../res/layout/new_voicemail_entry_alert.xml | 101 +++++++++++-- .../dialer/voicemail/listui/res/values/dimens.xml | 9 ++ 5 files changed, 281 insertions(+), 54 deletions(-) (limited to 'java/com/android/dialer/voicemail') diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java index 5519aa486..318f79783 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.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 } 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 /** 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 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 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 } 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 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 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 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 ec603b5c8..ac989a8df 100644 --- a/java/com/android/dialer/voicemail/listui/NewVoicemailAlertViewHolder.java +++ b/java/com/android/dialer/voicemail/listui/NewVoicemailAlertViewHolder.java @@ -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()); } } diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java index b4be42455..0d91f0158 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.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 { 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 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 e8dcd02d6..28d639118 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 --> - + - - + + - + 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"> + + + + + + + + + + + + +