Merge "Support deleting voicemails"
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
index 671a39a..a4848c8 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
@@ -16,23 +16,30 @@
package com.android.dialer.voicemail.listui;
import android.app.FragmentManager;
+import android.content.Context;
import android.database.Cursor;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
+import android.net.Uri;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.dialer.calllogutils.CallLogDates;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.DialerExecutor.SuccessListener;
+import com.android.dialer.common.concurrent.DialerExecutor.Worker;
+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;
@@ -69,6 +76,12 @@
private int currentlyExpandedViewHolderId = -1;
/**
+ * 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.
+ */
+ Set<Integer> deletedVoicemailPosition = new ArraySet<>();
+
+ /**
* A set of (re-usable) view holders being used by the recycler view to display voicemails. This
* set may include multiple view holder with the same ID and shouldn't be used to lookup a
* specific viewholder based on this value, instead use newVoicemailViewHolderArrayMap for that
@@ -130,6 +143,7 @@
}
public void updateCursor(Cursor updatedCursor) {
+ deletedVoicemailPosition.clear();
this.cursor = updatedCursor;
notifyDataSetChanged();
}
@@ -159,6 +173,20 @@
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
LogUtil.enterBlock("NewVoicemailAdapter.onBindViewHolder, pos:" + position);
+ // Re-request a bind when a viewholder is deleted to ensure correct position
+ if (deletedVoicemailPosition.contains(position)) {
+ LogUtil.i(
+ "NewVoicemailAdapter.onBindViewHolder",
+ "pos:%d contains deleted voicemail, re-bind. #of deleted voicemail positions: %d",
+ position,
+ deletedVoicemailPosition.size());
+ // TODO(uabdullah): This should be removed when we support multi-select delete
+ Assert.checkArgument(
+ deletedVoicemailPosition.size() == 1, "multi-deletes not currently supported");
+ onBindViewHolder(viewHolder, ++position);
+ return;
+ }
+
// TODO(uabdullah): a bug Remove logging, temporarily here for debugging.
printHashSet();
// TODO(uabdullah): a bug Remove logging, temporarily here for debugging.
@@ -464,6 +492,55 @@
onPreparedListener.onPrepared(mediaPlayer.getMediaPlayer());
}
+ @Override
+ public void deleteViewHolder(
+ Context context,
+ FragmentManager fragmentManager,
+ NewVoicemailViewHolder expandedViewHolder,
+ Uri voicemailUri) {
+ LogUtil.i(
+ "NewVoicemailAdapter.deleteViewHolder",
+ "deleting adapter position %d, id:%d, uri:%s ",
+ expandedViewHolder.getAdapterPosition(),
+ expandedViewHolder.getViewHolderId(),
+ String.valueOf(voicemailUri));
+
+ deletedVoicemailPosition.add(expandedViewHolder.getAdapterPosition());
+
+ Assert.checkArgument(expandedViewHolder.getViewHolderVoicemailUri().equals(voicemailUri));
+
+ notifyItemRemoved(expandedViewHolder.getAdapterPosition());
+
+ Assert.checkArgument(currentlyExpandedViewHolderId == expandedViewHolder.getViewHolderId());
+
+ collapseExpandedViewHolder(expandedViewHolder);
+
+ Worker<Pair<Context, Uri>, Integer> deleteVoicemail = this::deleteVoicemail;
+ SuccessListener<Integer> deleteVoicemailCallBack = this::onVoicemailDeleted;
+
+ DialerExecutorComponent.get(context)
+ .dialerExecutorFactory()
+ .createUiTaskBuilder(fragmentManager, "delete_voicemail", deleteVoicemail)
+ .onSuccess(deleteVoicemailCallBack)
+ .build()
+ .executeSerial(new Pair<>(context, voicemailUri));
+ }
+
+ private void onVoicemailDeleted(Integer integer) {
+ LogUtil.i("NewVoicemailAdapter.onVoicemailDeleted", "return value:%d", integer);
+ Assert.checkArgument(integer == 1, "voicemail delete was not successful");
+ }
+
+ @WorkerThread
+ private Integer deleteVoicemail(Pair<Context, Uri> contextUriPair) {
+ Assert.isWorkerThread();
+ LogUtil.enterBlock("NewVoicemailAdapter.deleteVoicemail");
+ Context context = contextUriPair.first;
+ Uri uri = contextUriPair.second;
+ LogUtil.i("NewVoicemailAdapter.deleteVoicemail", "deleting uri:%s", String.valueOf(uri));
+ return context.getContentResolver().delete(uri, null, null);
+ }
+
/**
* This function is called recursively to update the seekbar, duration, play/pause buttons of the
* expanded view holder if its playing.
@@ -731,6 +808,7 @@
@Override
public int getItemCount() {
+ // TODO(uabdullah): a bug Remove logging, temporarily here for debugging.
LogUtil.enterBlock("NewVoicemailAdapter.getItemCount");
int numberOfHeaders = 0;
if (todayHeaderPosition != Integer.MAX_VALUE) {
@@ -739,7 +817,14 @@
if (olderHeaderPosition != Integer.MAX_VALUE) {
numberOfHeaders++;
}
- return cursor.getCount() + numberOfHeaders;
+ // TODO(uabdullah): a bug Remove logging, temporarily here for debugging.
+ LogUtil.i(
+ "NewVoicemailAdapter.getItemCount",
+ "cursor cnt:%d, num of headers:%d, delete size:%d",
+ cursor.getCount(),
+ numberOfHeaders,
+ deletedVoicemailPosition.size());
+ return cursor.getCount() + numberOfHeaders - deletedVoicemailPosition.size();
}
@RowType
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java
index 82e704d..b4be424 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java
@@ -56,6 +56,7 @@
LogUtil.i("NewVoicemailFragment.onLoadFinished", "cursor size is %d", data.getCount());
if (recyclerView.getAdapter() == null) {
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+ // TODO(uabdullah): Replace getActivity().getFragmentManager() with getChildFragment()
recyclerView.setAdapter(
new NewVoicemailAdapter(
data, System::currentTimeMillis, getActivity().getFragmentManager()));
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java b/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java
index 3f2de7d..66a6fea 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java
@@ -379,8 +379,6 @@
private void sendIntentToDownloadVoicemail(Uri uri) {
LogUtil.i("NewVoicemailMediaPlayer.sendIntentToDownloadVoicemail", "uri:%s", uri.toString());
- // Send voicemail fetch request.
- Intent intent = new Intent(VoicemailContract.ACTION_FETCH_VOICEMAIL, uri);
Worker<Pair<Context, Uri>, Pair<String, Uri>> getVoicemailSourcePackage =
this::queryVoicemailSourcePackage;
@@ -399,7 +397,7 @@
Uri uri = booleanUriPair.second;
LogUtil.i(
"NewVoicemailMediaPlayer.sendIntent",
- "srcPkg:%s, uri:%%s",
+ "srcPkg:%s, uri:%s",
sourcePackage,
String.valueOf(uri));
Intent intent = new Intent(VoicemailContract.ACTION_FETCH_VOICEMAIL, uri);
@@ -465,6 +463,20 @@
"NewVoicemailMediaPlayer.phoneButtonListener",
"speaker request for voicemailUri: %s",
voicemailUri.toString());
+ ContentValues contentValues = new ContentValues();
+ contentValues.put("has_content", 0);
+ // TODO(uabdullah): It only sets the has_content to 0, to allow the annotated call log to
+ // change, and refresh the fragment. This is used to demo and test the downloading of
+ // voicemails from the server. This will be removed once we implement this listener.
+ try {
+ getContext().getContentResolver().update(voicemailUri, contentValues, "type = 4", null);
+ } catch (Exception e) {
+ LogUtil.i(
+ "NewVoicemailMediaPlayer.deleteButtonListener",
+ "update has content of voicemailUri %s caused an error: %s",
+ voicemailUri.toString(),
+ e.toString());
+ }
}
};
@@ -475,22 +487,9 @@
LogUtil.i(
"NewVoicemailMediaPlayer.deleteButtonListener",
"delete voicemailUri %s",
- voicemailUri.toString());
- // TODO(uabdullah): This will be removed in cl/177404259. It only sets the has_content to
- // 0, to allow the annotated call log to change, and refresh the fragment. This is used to
- // demo and test the downloading of voicemails from the server.
- ContentValues contentValues = new ContentValues();
- contentValues.put("has_content", 0);
-
- try {
- getContext().getContentResolver().update(voicemailUri, contentValues, "type = 4", null);
- } catch (Exception e) {
- LogUtil.i(
- "NewVoicemailMediaPlayer.deleteButtonListener",
- "update has content of voicemailUri %s caused an error: %s",
- voicemailUri.toString(),
- e.toString());
- }
+ String.valueOf(voicemailUri));
+ newVoicemailViewHolderListener.deleteViewHolder(
+ getContext(), fragmentManager, newVoicemailViewHolder, voicemailUri);
}
};
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
index 0725465..bc23288 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
@@ -363,6 +363,12 @@
void pauseViewHolder(NewVoicemailViewHolder expandedViewHolder);
void resumePausedViewHolder(NewVoicemailViewHolder expandedViewHolder);
+
+ void deleteViewHolder(
+ Context context,
+ FragmentManager fragmentManager,
+ NewVoicemailViewHolder expandedViewHolder,
+ Uri uri);
}
@Override