Play voicemails downloaded from the voicemail server in the NUI VM Fragment
Voicemails that are available locally on the device (have been downloaded from the voicemail server) will have their "HAS_CONTENT" column set to one. This CL adds the plumbing logic of checking that when a user presses the play button, if the voicemail is available locally, it is played.
Bug: 64882313,68382421
Test: Existing unit tests
PiperOrigin-RevId: 175590204
Change-Id: Id164d08c16b89c84a75af0c4a7c899c02d64fff7
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
index d04143f..6f6a87c 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java
@@ -15,6 +15,7 @@
*/
package com.android.dialer.voicemail.listui;
+import android.app.FragmentManager;
import android.database.Cursor;
import android.support.v7.widget.RecyclerView;
import android.util.ArraySet;
@@ -33,6 +34,7 @@
private final Cursor cursor;
private final Clock clock;
+ private final FragmentManager fragmentManager;
/** A valid id for {@link VoicemailEntry} is greater than 0 */
private int currentlyExpandedViewHolderId = -1;
@@ -40,13 +42,16 @@
private final Set<NewVoicemailViewHolder> newVoicemailViewHolderSet = new ArraySet<>();
/** @param cursor whose projection is {@link VoicemailCursorLoader.VOICEMAIL_COLUMNS} */
- NewVoicemailAdapter(Cursor cursor, Clock clock) {
+ NewVoicemailAdapter(Cursor cursor, Clock clock, FragmentManager fragmentManager) {
+ LogUtil.enterBlock("NewVoicemailAdapter");
this.cursor = cursor;
this.clock = clock;
+ this.fragmentManager = fragmentManager;
}
@Override
public NewVoicemailViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
+ LogUtil.enterBlock("NewVoicemailAdapter.onCreateViewHolder");
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
View view = inflater.inflate(R.layout.new_voicemail_entry, viewGroup, false);
NewVoicemailViewHolder newVoicemailViewHolder = new NewVoicemailViewHolder(view, clock, this);
@@ -56,9 +61,8 @@
@Override
public void onBindViewHolder(NewVoicemailViewHolder viewHolder, int position) {
- LogUtil.i("onBindViewHolder", "position" + position);
cursor.moveToPosition(position);
- viewHolder.bind(cursor);
+ viewHolder.bind(cursor, fragmentManager);
expandOrCollapseViewHolder(viewHolder);
}
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java
index 9c1fd8b..9a89dbe 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java
@@ -54,7 +54,9 @@
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
LogUtil.i("NewVoicemailFragment.onCreateLoader", "cursor size is %d", data.getCount());
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
- recyclerView.setAdapter(new NewVoicemailAdapter(data, System::currentTimeMillis));
+ recyclerView.setAdapter(
+ new NewVoicemailAdapter(
+ data, System::currentTimeMillis, getActivity().getFragmentManager()));
}
@Override
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayer.java b/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayer.java
deleted file mode 100644
index 11aa9ac..0000000
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayer.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dialer.voicemail.listui;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import com.android.dialer.common.LogUtil;
-
-/**
- * The view of the media player that is visible when a {@link NewVoicemailViewHolder} is expanded.
- */
-public class NewVoicemailMediaPlayer extends LinearLayout {
-
- private Button playButton;
- private Button speakerButton;
- private Button deleteButton;
-
- public NewVoicemailMediaPlayer(Context context, AttributeSet attrs) {
- super(context, attrs);
- LogUtil.enterBlock("NewVoicemailMediaPlayer");
- LayoutInflater inflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(R.layout.new_voicemail_media_player_layout, this);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- LogUtil.enterBlock("NewVoicemailMediaPlayer.onFinishInflate");
- initializeMediaPlayerButtons();
- setupListenersForMediaPlayerButtons();
- }
-
- private void initializeMediaPlayerButtons() {
- playButton = findViewById(R.id.playButton);
- speakerButton = findViewById(R.id.speakerButton);
- deleteButton = findViewById(R.id.deleteButton);
- }
-
- private void setupListenersForMediaPlayerButtons() {
- playButton.setOnClickListener(playButtonListener);
- speakerButton.setOnClickListener(speakerButtonListener);
- deleteButton.setOnClickListener(deleteButtonListener);
- }
-
- private final View.OnClickListener playButtonListener =
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- LogUtil.i("NewVoicemailMediaPlayer.playButtonListener", "onClick");
- }
- };
-
- private final View.OnClickListener speakerButtonListener =
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- LogUtil.i("NewVoicemailMediaPlayer.speakerButtonListener", "onClick");
- }
- };
-
- private final View.OnClickListener deleteButtonListener =
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- LogUtil.i("NewVoicemailMediaPlayer.deleteButtonListener", "onClick");
- }
- };
-}
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java b/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java
new file mode 100644
index 0000000..1e56a81
--- /dev/null
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailMediaPlayerView.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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.provider.VoicemailContract;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.util.Pair;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+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;
+
+/**
+ * The view of the media player that is visible when a {@link NewVoicemailViewHolder} is expanded.
+ */
+public class NewVoicemailMediaPlayerView extends LinearLayout {
+
+ private Button playButton;
+ private Button speakerButton;
+ private Button deleteButton;
+ private Uri voicemailUri;
+ private FragmentManager fragmentManager;
+ private MediaPlayer mediaPlayer;
+
+ public NewVoicemailMediaPlayerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ LogUtil.enterBlock("NewVoicemailMediaPlayer");
+ LayoutInflater inflater =
+ (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.new_voicemail_media_player_layout, this);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ LogUtil.enterBlock("NewVoicemailMediaPlayer.onFinishInflate");
+ initializeMediaPlayerButtons();
+ setupListenersForMediaPlayerButtons();
+ }
+
+ private void initializeMediaPlayerButtons() {
+ playButton = findViewById(R.id.playButton);
+ speakerButton = findViewById(R.id.speakerButton);
+ deleteButton = findViewById(R.id.deleteButton);
+ }
+
+ private void setupListenersForMediaPlayerButtons() {
+ playButton.setOnClickListener(playButtonListener);
+ speakerButton.setOnClickListener(speakerButtonListener);
+ deleteButton.setOnClickListener(deleteButtonListener);
+ }
+
+ private final View.OnClickListener playButtonListener =
+ view -> playVoicemailWhenAvailableLocally();
+
+ /**
+ * Plays the voicemail when we are able to play the voicemail locally from the device. This
+ * involves checking if the voicemail is available to play locally, if it is, then we setup the
+ * Media Player to play the voicemail. If the voicemail is not available, then we need download
+ * the voicemail from the voicemail server to the device, and then have the Media player play it.
+ */
+ private void playVoicemailWhenAvailableLocally() {
+ LogUtil.enterBlock("playVoicemailWhenAvailableLocally");
+ Worker<Pair<Context, Uri>, Pair<Boolean, Uri>> checkVoicemailHasContent =
+ this::queryVoicemailHasContent;
+ SuccessListener<Pair<Boolean, Uri>> checkVoicemailHasContentCallBack = this::prepareMediaPlayer;
+
+ DialerExecutorComponent.get(getContext())
+ .dialerExecutorFactory()
+ .createUiTaskBuilder(fragmentManager, "lookup_voicemail_content", checkVoicemailHasContent)
+ .onSuccess(checkVoicemailHasContentCallBack)
+ .build()
+ .executeSerial(new Pair<>(getContext(), voicemailUri));
+ }
+
+ private Pair<Boolean, Uri> queryVoicemailHasContent(Pair<Context, Uri> contextUriPair) {
+ Context context = contextUriPair.first;
+ Uri uri = contextUriPair.second;
+
+ try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
+ if (cursor != null && cursor.moveToNext()) {
+ return new Pair<>(
+ cursor.getInt(cursor.getColumnIndex(VoicemailContract.Voicemails.HAS_CONTENT)) == 1,
+ uri);
+ }
+ return new Pair<>(false, uri);
+ }
+ }
+
+ /**
+ * If the voicemail is available to play locally, setup the media player to play it. Otherwise
+ * send a request to download the voicemail and then play it.
+ */
+ private void prepareMediaPlayer(Pair<Boolean, Uri> booleanUriPair) {
+ boolean voicemailAvailableLocally = booleanUriPair.first;
+ Uri uri = booleanUriPair.second;
+ LogUtil.i(
+ "NewVoicemailMediaPlayer.prepareMediaPlayer",
+ "voicemail available locally: %b for voicemailUri: %s",
+ voicemailAvailableLocally,
+ uri.toString());
+
+ if (voicemailAvailableLocally) {
+ try {
+ mediaPlayer = new MediaPlayer();
+ mediaPlayer.setOnPreparedListener(onPreparedListener);
+ mediaPlayer.setOnErrorListener(onErrorListener);
+ mediaPlayer.setOnCompletionListener(onCompletionListener);
+
+ mediaPlayer.reset();
+ mediaPlayer.setDataSource(getContext(), uri);
+
+ mediaPlayer.prepareAsync();
+ } catch (Exception e) {
+ LogUtil.e("NewVoicemailMediaPlayer.prepareMediaPlayer", "IOException " + e);
+ }
+ } else {
+ // TODO(a bug): Add logic for downloading voicemail content from the server.
+ LogUtil.i(
+ "NewVoicemailMediaPlayer.prepareVoicemailForMediaPlayer", "need to download content");
+ }
+ }
+
+ private final View.OnClickListener speakerButtonListener =
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ LogUtil.i(
+ "NewVoicemailMediaPlayer.speakerButtonListener",
+ "speaker request for voicemailUri: %s",
+ voicemailUri.toString());
+ }
+ };
+
+ private final View.OnClickListener deleteButtonListener =
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ LogUtil.i(
+ "NewVoicemailMediaPlayer.deleteButtonListener",
+ "delete voicemailUri %s",
+ voicemailUri.toString());
+ }
+ };
+
+ @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+ OnCompletionListener onCompletionListener =
+ new OnCompletionListener() {
+
+ @Override
+ public void onCompletion(MediaPlayer mp) {
+ LogUtil.i(
+ "NewVoicemailMediaPlayer.onCompletionListener",
+ "completed playing voicemailUri: %s",
+ voicemailUri.toString());
+ }
+ };
+
+ private final OnPreparedListener onPreparedListener =
+ new OnPreparedListener() {
+
+ @Override
+ public void onPrepared(MediaPlayer mp) {
+ LogUtil.i(
+ "NewVoicemailMediaPlayer.onPreparedListener",
+ "about to play voicemailUri: %s",
+ voicemailUri.toString());
+ mediaPlayer.start();
+ }
+ };
+
+ @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+ OnErrorListener onErrorListener =
+ new OnErrorListener() {
+ @Override
+ public boolean onError(MediaPlayer mp, int what, int extra) {
+ LogUtil.i(
+ "NewVoicemailMediaPlayer.onErrorListener",
+ "error playing voicemailUri: %s",
+ voicemailUri.toString());
+ return false;
+ }
+ };
+
+ public void setVoicemailUri(Uri voicemailUri) {
+ Assert.isNotNull(voicemailUri);
+ this.voicemailUri = voicemailUri;
+ }
+
+ public void setFragmentManager(FragmentManager fragmentManager) {
+ this.fragmentManager = fragmentManager;
+ }
+}
diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
index d4bfefd..078a029 100644
--- a/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
+++ b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java
@@ -15,6 +15,7 @@
*/
package com.android.dialer.voicemail.listui;
+import android.app.FragmentManager;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
@@ -25,6 +26,7 @@
import android.view.View.OnClickListener;
import android.widget.QuickContactBadge;
import android.widget.TextView;
+import com.android.dialer.common.LogUtil;
import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.lettertile.LetterTileDrawable;
import com.android.dialer.time.Clock;
@@ -38,7 +40,7 @@
private final TextView secondaryTextView;
private final TextView transcriptionTextView;
private final QuickContactBadge quickContactBadge;
- private final View mediaPlayerView;
+ private final NewVoicemailMediaPlayerView mediaPlayerView;
private final Clock clock;
private boolean isViewHolderExpanded;
private int viewHolderId;
@@ -47,6 +49,7 @@
NewVoicemailViewHolder(
View view, Clock clock, NewVoicemailViewHolderListener newVoicemailViewHolderListener) {
super(view);
+ LogUtil.enterBlock("NewVoicemailViewHolder");
this.context = view.getContext();
primaryTextView = view.findViewById(R.id.primary_text);
secondaryTextView = view.findViewById(R.id.secondary_text);
@@ -57,7 +60,7 @@
voicemailViewHolderListener = newVoicemailViewHolderListener;
}
- void bind(Cursor cursor) {
+ void bind(Cursor cursor, FragmentManager fragmentManager) {
VoicemailEntry voicemailEntry = VoicemailCursorLoader.toVoicemailEntry(cursor);
viewHolderId = voicemailEntry.id();
primaryTextView.setText(VoicemailEntryText.buildPrimaryVoicemailText(context, voicemailEntry));
@@ -76,6 +79,8 @@
itemView.setOnClickListener(this);
setPhoto(voicemailEntry);
+ mediaPlayerView.setVoicemailUri(Uri.parse(voicemailEntry.voicemailUri()));
+ mediaPlayerView.setFragmentManager(fragmentManager);
}
// TODO(uabdullah): Consider/Implement TYPE (e.g Spam, TYPE_VOICEMAIL)
@@ -97,6 +102,7 @@
}
void expandViewHolder() {
+ LogUtil.i("NewVoicemailViewHolder.expandViewHolder", "voicemail id: %d", viewHolderId);
transcriptionTextView.setMaxLines(999);
isViewHolderExpanded = true;
mediaPlayerView.setVisibility(View.VISIBLE);
@@ -117,6 +123,7 @@
@Override
public void onClick(View v) {
+ LogUtil.i("NewVoicemailViewHolder.onClick", "voicemail id: %d", viewHolderId);
if (isViewHolderExpanded) {
collapseViewHolder();
} else {
diff --git a/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_entry.xml b/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_entry.xml
index 80bb1b5..78d2785 100644
--- a/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_entry.xml
+++ b/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_entry.xml
@@ -82,7 +82,7 @@
android:layout_gravity="center_vertical"
android:visibility="gone"/>
- <com.android.dialer.voicemail.listui.NewVoicemailMediaPlayer
+ <com.android.dialer.voicemail.listui.NewVoicemailMediaPlayerView
android:id="@+id/new_voicemail_media_player"
android:layout_width="match_parent"
android:layout_height="wrap_content"