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

Commit 04706000 authored by uabdullah's avatar uabdullah Committed by android-build-merger
Browse files

Merge "Implement today and older for NUI Voicemail and update MediaPlayerView...

Merge "Implement today and older for NUI Voicemail and update MediaPlayerView tests" am: ab544521 am: bc61f422
am: 93e88718

Change-Id: I29c942726fd027517d143c81f08b2b196ea6486e
parents 5125143e 93e88718
Loading
Loading
Loading
Loading
+220 −23
Original line number Original line Diff line number Diff line
@@ -21,28 +21,49 @@ import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.ArraySet;
import android.view.LayoutInflater;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup;
import com.android.dialer.calllogutils.CallLogDates;
import com.android.dialer.common.Assert;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.ThreadUtil;
import com.android.dialer.common.concurrent.ThreadUtil;
import com.android.dialer.time.Clock;
import com.android.dialer.time.Clock;
import com.android.dialer.voicemail.listui.NewVoicemailViewHolder.NewVoicemailViewHolderListener;
import com.android.dialer.voicemail.listui.NewVoicemailViewHolder.NewVoicemailViewHolderListener;
import com.android.dialer.voicemail.model.VoicemailEntry;
import com.android.dialer.voicemail.model.VoicemailEntry;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
import java.util.Objects;
import java.util.Set;
import java.util.Set;


/** {@link RecyclerView.Adapter} for the new voicemail call log fragment. */
/** {@link RecyclerView.Adapter} for the new voicemail call log fragment. */
final class NewVoicemailAdapter extends RecyclerView.Adapter<NewVoicemailViewHolder>
final class NewVoicemailAdapter extends RecyclerView.Adapter<ViewHolder>
    implements NewVoicemailViewHolderListener {
    implements NewVoicemailViewHolderListener {


  /** IntDef for the different types of rows that can be shown in the call log. */
  @Retention(RetentionPolicy.SOURCE)
  @IntDef({RowType.HEADER, RowType.VOICEMAIL_ENTRY})
  @interface RowType {
    /** Header that displays "Today" or "Older". */
    int HEADER = 1;
    /** A row representing a voicemail entry. */
    int VOICEMAIL_ENTRY = 2;
  }

  private final Cursor cursor;
  private final Cursor cursor;
  private final Clock clock;
  private final Clock clock;

  /** {@link Integer#MAX_VALUE} when the "Today" header should not be displayed. */
  private final int todayHeaderPosition;
  /** {@link Integer#MAX_VALUE} when the "Older" header should not be displayed. */
  private final int olderHeaderPosition;

  private final FragmentManager fragmentManager;
  private final FragmentManager fragmentManager;
  /** A valid id for {@link VoicemailEntry} is greater than 0 */
  /** A valid id for {@link VoicemailEntry} is greater than 0 */
  private int currentlyExpandedViewHolderId = -1;
  private int currentlyExpandedViewHolderId = -1;
@@ -73,6 +94,33 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<NewVoicemailViewHol
    this.clock = clock;
    this.clock = clock;
    this.fragmentManager = fragmentManager;
    this.fragmentManager = fragmentManager;
    initializeMediaPlayerListeners();
    initializeMediaPlayerListeners();

    // Calculate header adapter positions by reading cursor.
    long currentTimeMillis = clock.currentTimeMillis();
    if (cursor.moveToNext()) {
      long firstTimestamp = VoicemailCursorLoader.getTimestamp(cursor);
      if (CallLogDates.isSameDay(currentTimeMillis, firstTimestamp)) {
        this.todayHeaderPosition = 0;
        int adapterPosition = 2; // Accounted for "Today" header and first row.
        while (cursor.moveToNext()) {
          long timestamp = VoicemailCursorLoader.getTimestamp(cursor);

          if (CallLogDates.isSameDay(currentTimeMillis, timestamp)) {
            adapterPosition++;
          } else {
            this.olderHeaderPosition = adapterPosition;
            return;
          }
        }
        this.olderHeaderPosition = Integer.MAX_VALUE; // Didn't find any "Older" rows.
      } else {
        this.todayHeaderPosition = Integer.MAX_VALUE; // Didn't find any "Today" rows.
        this.olderHeaderPosition = 0;
      }
    } else { // There are no rows, just need to set these because they are final.
      this.todayHeaderPosition = Integer.MAX_VALUE;
      this.olderHeaderPosition = Integer.MAX_VALUE;
    }
  }
  }


  private void initializeMediaPlayerListeners() {
  private void initializeMediaPlayerListeners() {
@@ -82,41 +130,123 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<NewVoicemailViewHol
  }
  }


  @Override
  @Override
  public NewVoicemailViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
  public ViewHolder onCreateViewHolder(ViewGroup viewGroup, @RowType int viewType) {
    LogUtil.enterBlock("NewVoicemailAdapter.onCreateViewHolder");
    LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
    LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
    View view = inflater.inflate(R.layout.new_voicemail_entry, viewGroup, false);
    View view;
    NewVoicemailViewHolder newVoicemailViewHolder = new NewVoicemailViewHolder(view, clock, this);
    switch (viewType) {
      case RowType.HEADER:
        view = inflater.inflate(R.layout.new_voicemail_entry_header, viewGroup, false);
        return new NewVoicemailHeaderViewHolder(view);
      case NewVoicemailAdapter.RowType.VOICEMAIL_ENTRY:
        view = inflater.inflate(R.layout.new_voicemail_entry, viewGroup, false);
        NewVoicemailViewHolder newVoicemailViewHolder =
            new NewVoicemailViewHolder(view, clock, this);
        newVoicemailViewHolderSet.add(newVoicemailViewHolder);
        newVoicemailViewHolderSet.add(newVoicemailViewHolder);
        return newVoicemailViewHolder;
        return newVoicemailViewHolder;
      default:
        throw Assert.createUnsupportedOperationFailException("Unsupported view type: " + viewType);
    }
  }
  }


  // TODO(uabdullah): a bug - Clean up logging in this function, here for debugging during
  // development.
  @Override
  @Override
  public void onBindViewHolder(NewVoicemailViewHolder viewHolder, int position) {
  public void onBindViewHolder(ViewHolder viewHolder, int position) {
    LogUtil.enterBlock("NewVoicemailAdapter.onBindViewHolder, pos:" + position);
    // TODO(uabdullah): a bug Remove logging, temporarily here for debugging.
    printHashSet();
    // TODO(uabdullah): a bug Remove logging, temporarily here for debugging.
    printHashMap();

    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 == olderHeaderPosition) {
        headerViewHolder.setHeader(R.string.new_voicemail_header_older);
      } else {
        throw Assert.createIllegalStateFailException(
            "Unexpected view type " + viewType + " at position: " + position);
      }
      return;
    }

    LogUtil.i(
        "NewVoicemailAdapter.onBindViewHolder",
        "view holder at pos:%d is a not a header",
        position);

    NewVoicemailViewHolder newVoicemailViewHolder = (NewVoicemailViewHolder) viewHolder;

    int previousHeaders = 0;
    if (todayHeaderPosition != Integer.MAX_VALUE && position > todayHeaderPosition) {
      previousHeaders++;
    }
    if (olderHeaderPosition != Integer.MAX_VALUE && position > olderHeaderPosition) {
      previousHeaders++;
    }

    LogUtil.i(
        "NewVoicemailAdapter.onBindViewHolder",
        "view holder at pos:%d, prevHeaderCount:%d",
        position,
        previousHeaders);

    // Remove if the viewholder is being recycled.
    // Remove if the viewholder is being recycled.
    if (newVoicemailViewHolderArrayMap.containsKey(viewHolder.getViewHolderId())) {
    if (newVoicemailViewHolderArrayMap.containsKey(newVoicemailViewHolder.getViewHolderId())) {
      // TODO(uabdullah): Remove the logging, only here for debugging during development.
      // TODO(uabdullah): a bug Remove logging, temporarily here for debugging.
      LogUtil.i(
      LogUtil.i(
          "NewVoicemailAdapter.onBindViewHolder",
          "NewVoicemailAdapter.onBindViewHolder",
          "Removing from hashset:%d, hashsetSize:%d",
          "Removing from hashset:%d, hashsetSize:%d, currExpanded:%d",
          viewHolder.getViewHolderId(),
          newVoicemailViewHolder.getViewHolderId(),
          newVoicemailViewHolderArrayMap.size());
          newVoicemailViewHolderArrayMap.size(),
          currentlyExpandedViewHolderId);


      newVoicemailViewHolderArrayMap.remove(viewHolder.getViewHolderId());
      newVoicemailViewHolderArrayMap.remove(newVoicemailViewHolder.getViewHolderId());
      printHashSet();
      printHashMap();
    }
    }


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


    // TODO(uabdullah): a bug Remove logging, temporarily here for debugging.
    LogUtil.i(
        "NewVoicemailAdapter.onBindViewHolder",
        "Adding to hashset:%d, hashsetSize:%d, pos:%d, currExpanded:%d",
        newVoicemailViewHolder.getViewHolderId(),
        newVoicemailViewHolderArrayMap.size(),
        position,
        currentlyExpandedViewHolderId);

    // Need this to ensure correct getCurrentlyExpandedViewHolder() value
    // Need this to ensure correct getCurrentlyExpandedViewHolder() value
    newVoicemailViewHolderArrayMap.put(viewHolder.getViewHolderId(), viewHolder);
    newVoicemailViewHolderArrayMap.put(
        newVoicemailViewHolder.getViewHolderId(), newVoicemailViewHolder);

    // TODO(uabdullah): a bug Remove logging, temporarily here for debugging.
    printHashSet();
    // TODO(uabdullah): a bug Remove logging, temporarily here for debugging.
    printHashMap();


    // If the viewholder is playing the voicemail, keep updating its media player view (seekbar,
    // If the viewholder is playing the voicemail, keep updating its media player view (seekbar,
    // duration etc.)
    // duration etc.)
    if (viewHolder.isViewHolderExpanded() && mediaPlayer.isPlaying()) {
    if (newVoicemailViewHolder.isViewHolderExpanded() && mediaPlayer.isPlaying()) {
      LogUtil.i(
          "NewVoicemailAdapter.onBindViewHolder",
          "Adding to hashset:%d, hashsetSize:%d, pos:%d, currExpanded:%d",
          newVoicemailViewHolderSet.size(),
          newVoicemailViewHolderArrayMap.size(),
          position,
          currentlyExpandedViewHolderId);

      Assert.checkArgument(
      Assert.checkArgument(
          viewHolder
          newVoicemailViewHolder
              .getViewHolderVoicemailUri()
              .getViewHolderVoicemailUri()
              .equals(mediaPlayer.getLastPlayedOrPlayingVoicemailUri()),
              .equals(mediaPlayer.getLastPlayedOrPlayingVoicemailUri()),
          "only the expanded view holder can be playing.");
          "only the expanded view holder can be playing.");
@@ -126,10 +256,48 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<NewVoicemailViewHol
              .getViewHolderVoicemailUri()
              .getViewHolderVoicemailUri()
              .equals(mediaPlayer.getLastPlayedOrPlayingVoicemailUri()));
              .equals(mediaPlayer.getLastPlayedOrPlayingVoicemailUri()));


      recursivelyUpdateMediaPlayerViewOfExpandedViewHolder(viewHolder);
      recursivelyUpdateMediaPlayerViewOfExpandedViewHolder(newVoicemailViewHolder);
    }
    }
    // Updates the hashmap with the most up-to-date state of the viewholder.
    // Updates the hashmap with the most up-to-date state of the viewholder.
    newVoicemailViewHolderArrayMap.put(viewHolder.getViewHolderId(), viewHolder);
    newVoicemailViewHolderArrayMap.put(
        newVoicemailViewHolder.getViewHolderId(), newVoicemailViewHolder);

    // TODO(uabdullah): a bug Remove logging, temporarily here for debugging.
    printHashSet();
    // TODO(uabdullah): a bug Remove logging, temporarily here for debugging.
    printHashMap();
  }

  private void printHashMap() {
    LogUtil.i(
        "NewVoicemailAdapter.printHashMap",
        "hashMapSize: %d, currentlyExpandedViewHolderId:%d",
        newVoicemailViewHolderArrayMap.size(),
        currentlyExpandedViewHolderId);

    if (!newVoicemailViewHolderArrayMap.isEmpty()) {
      String ids = "";
      for (int id : newVoicemailViewHolderArrayMap.keySet()) {
        ids = id + String.valueOf(id) + " ";
      }
      LogUtil.i("NewVoicemailAdapter.printHashMap", "ids are " + ids);
    }
  }

  private void printHashSet() {
    LogUtil.i(
        "NewVoicemailAdapter.printHashSet",
        "hashSetSize: %d, currentlyExpandedViewHolderId:%d",
        newVoicemailViewHolderSet.size(),
        currentlyExpandedViewHolderId);

    if (!newVoicemailViewHolderSet.isEmpty()) {
      String viewHolderID = "";
      for (NewVoicemailViewHolder vh : newVoicemailViewHolderSet) {
        viewHolderID = viewHolderID + vh.getViewHolderId() + " ";
      }
      LogUtil.i("NewVoicemailAdapter.printHashSet", "ids are " + viewHolderID);
    }
  }
  }


  /**
  /**
@@ -316,6 +484,11 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<NewVoicemailViewHol
   */
   */
  private void recursivelyUpdateMediaPlayerViewOfExpandedViewHolder(
  private void recursivelyUpdateMediaPlayerViewOfExpandedViewHolder(
      NewVoicemailViewHolder expandedViewHolderPossiblyPlaying) {
      NewVoicemailViewHolder expandedViewHolderPossiblyPlaying) {
    // TODO(uabdullah): a bug Remove logging, temporarily here for debugging.
    LogUtil.i(
        "NewVoicemailAdapter.recursivelyUpdateMediaPlayerViewOfExpandedViewHolder",
        "currentlyExpanded:%d",
        currentlyExpandedViewHolderId);


    // It's possible that by the time this is run, the expanded view holder has been
    // It's possible that by the time this is run, the expanded view holder has been
    // scrolled out of view (and possibly recycled)
    // scrolled out of view (and possibly recycled)
@@ -368,7 +541,7 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<NewVoicemailViewHol
          mediaPlayer
          mediaPlayer
              .getLastPlayedOrPlayingVoicemailUri()
              .getLastPlayedOrPlayingVoicemailUri()
              .equals(getCurrentlyExpandedViewHolder().getViewHolderVoicemailUri()));
              .equals(getCurrentlyExpandedViewHolder().getViewHolderVoicemailUri()));
      // TODO(uabdullah): Remove this, here for debugging during development.
      // TODO(uabdullah): a bug Remove logging, temporarily here for debugging.
      LogUtil.i(
      LogUtil.i(
          "NewVoicemailAdapter.recursivelyUpdateMediaPlayerViewOfExpandedViewHolder",
          "NewVoicemailAdapter.recursivelyUpdateMediaPlayerViewOfExpandedViewHolder",
          "recursely update the player, currentlyExpanded:%d",
          "recursely update the player, currentlyExpanded:%d",
@@ -544,12 +717,36 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter<NewVoicemailViewHol
          "no view holder found in newVoicemailViewHolderArrayMap size:%d for %d",
          "no view holder found in newVoicemailViewHolderArrayMap size:%d for %d",
          newVoicemailViewHolderArrayMap.size(),
          newVoicemailViewHolderArrayMap.size(),
          currentlyExpandedViewHolderId);
          currentlyExpandedViewHolderId);
      // TODO(uabdullah): a bug Remove logging, temporarily here for debugging.
      printHashSet();
      printHashMap();
      return null;
      return null;
    }
    }
  }
  }


  @Override
  @Override
  public int getItemCount() {
  public int getItemCount() {
    return cursor.getCount();
    LogUtil.enterBlock("NewVoicemailAdapter.getItemCount");
    int numberOfHeaders = 0;
    if (todayHeaderPosition != Integer.MAX_VALUE) {
      numberOfHeaders++;
    }
    if (olderHeaderPosition != Integer.MAX_VALUE) {
      numberOfHeaders++;
    }
    return cursor.getCount() + numberOfHeaders;
  }

  @RowType
  @Override
  public int getItemViewType(int position) {
    LogUtil.enterBlock("NewVoicemailAdapter.getItemViewType");
    if (todayHeaderPosition != Integer.MAX_VALUE && position == todayHeaderPosition) {
      return RowType.HEADER;
    }
    if (olderHeaderPosition != Integer.MAX_VALUE && position == olderHeaderPosition) {
      return RowType.HEADER;
    }
    return RowType.VOICEMAIL_ENTRY;
  }
  }
}
}
+43 −0
Original line number Original line Diff line number Diff line
/*
 * 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.support.annotation.StringRes;
import android.support.annotation.VisibleForTesting;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View;
import android.widget.TextView;

/** ViewHolder for {@link NewVoicemailAdapter} to display "Today" or "Older" divider row. */
final class NewVoicemailHeaderViewHolder extends ViewHolder {

  private final TextView headerTextView;

  NewVoicemailHeaderViewHolder(View view) {
    super(view);
    headerTextView = view.findViewById(R.id.new_voicemail_header_text);
  }

  void setHeader(@StringRes int header) {
    headerTextView.setText(header);
  }

  @VisibleForTesting(otherwise = VisibleForTesting.NONE)
  String getHeaderText() {
    return headerTextView.getText().toString();
  }
}
+10 −0
Original line number Original line Diff line number Diff line
@@ -92,8 +92,18 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On
      int position,
      int position,
      int currentlyExpandedViewHolderId) {
      int currentlyExpandedViewHolderId) {


    LogUtil.i(
        "NewVoicemailViewHolder.bindViewHolderValuesFromAdapter",
        "view holder at pos:%d, adapterPos:%d, cursorPos:%d, cursorSize:%d",
        position,
        getAdapterPosition(),
        cursor.getPosition(),
        cursor.getCount());

    voicemailEntryOfViewHolder = VoicemailCursorLoader.toVoicemailEntry(cursor);
    voicemailEntryOfViewHolder = VoicemailCursorLoader.toVoicemailEntry(cursor);
    viewHolderId = voicemailEntryOfViewHolder.id();
    viewHolderId = voicemailEntryOfViewHolder.id();
    LogUtil.i(
        "NewVoicemailViewHolder.bindViewHolderValuesFromAdapter", "viewholderId:%d", viewHolderId);
    viewHolderVoicemailUri = Uri.parse(voicemailEntryOfViewHolder.voicemailUri());
    viewHolderVoicemailUri = Uri.parse(voicemailEntryOfViewHolder.voicemailUri());
    primaryTextView.setText(
    primaryTextView.setText(
        VoicemailEntryText.buildPrimaryVoicemailText(context, voicemailEntryOfViewHolder));
        VoicemailEntryText.buildPrimaryVoicemailText(context, voicemailEntryOfViewHolder));
+4 −0
Original line number Original line Diff line number Diff line
@@ -97,4 +97,8 @@ final class VoicemailCursorLoader extends CursorLoader {
        .setCallType(cursor.getInt(CALL_TYPE))
        .setCallType(cursor.getInt(CALL_TYPE))
        .build();
        .build();
  }
  }

  static long getTimestamp(Cursor cursor) {
    return cursor.getLong(TIMESTAMP);
  }
}
}
+29 −0
Original line number Original line Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ 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
  -->
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="48dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
  <TextView
      android:id="@+id/new_voicemail_header_text"
      style="@style/SecondaryText"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginStart="@dimen/voicemail_header_margin_start"
      android:layout_centerVertical="true"/>
</RelativeLayout>
Loading