Adding support for video call icon and data usage in call log.

Bug: 16013684
Bug: 16015261
Change-Id: Ie75443d641c1e09a5772bb618aba55de8583716b
diff --git a/src/com/android/dialer/CallDetailActivity.java b/src/com/android/dialer/CallDetailActivity.java
index fa8d5ed..3ef78af 100644
--- a/src/com/android/dialer/CallDetailActivity.java
+++ b/src/com/android/dialer/CallDetailActivity.java
@@ -50,6 +50,7 @@
 import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
 import com.android.contacts.common.GeoUtil;
 import com.android.dialer.calllog.CallDetailHistoryAdapter;
+import com.android.dialer.calllog.CallLogQuery;
 import com.android.dialer.calllog.CallTypeHelper;
 import com.android.dialer.calllog.ContactInfo;
 import com.android.dialer.calllog.ContactInfoHelper;
@@ -197,6 +198,8 @@
         CallLog.Calls.NUMBER_PRESENTATION,
         CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME,
         CallLog.Calls.PHONE_ACCOUNT_ID,
+        CallLog.Calls.FEATURES,
+        CallLog.Calls.DATA_USAGE
     };
 
     static final int DATE_COLUMN_INDEX = 0;
@@ -208,6 +211,8 @@
     static final int NUMBER_PRESENTATION_COLUMN_INDEX = 6;
     static final int ACCOUNT_COMPONENT_NAME = 7;
     static final int ACCOUNT_ID = 8;
+    static final int FEATURES = 9;
+    static final int DATA_USAGE = 10;
 
     @Override
     protected void onCreate(Bundle icicle) {
@@ -525,11 +530,16 @@
                 lookupUri = info.lookupUri;
                 sourceType = info.sourceType;
             }
+            final int features = callCursor.getInt(FEATURES);
+            Long dataUsage = null;
+            if (!callCursor.isNull(DATA_USAGE)) {
+                dataUsage = callCursor.getLong(DATA_USAGE);
+            }
             return new PhoneCallDetails(number, numberPresentation,
                     formattedNumber, countryIso, geocode,
                     new int[]{ callType }, date, duration,
                     nameText, numberType, numberLabel, lookupUri, photoUri, sourceType,
-                    accountIcon);
+                    accountIcon, features, dataUsage);
         } finally {
             if (callCursor != null) {
                 callCursor.close();
diff --git a/src/com/android/dialer/PhoneCallDetails.java b/src/com/android/dialer/PhoneCallDetails.java
index afdb2e3..0dc6fd3 100644
--- a/src/com/android/dialer/PhoneCallDetails.java
+++ b/src/com/android/dialer/PhoneCallDetails.java
@@ -68,13 +68,23 @@
      * The unique identifier for the provider associated with the call.
      */
     public final Drawable accountIcon;
+    /**
+     * Features applicable to this call.
+     */
+    public final int features;
+    /**
+     * Total data usage for this call.
+     */
+    public final Long dataUsage;
 
     /** Create the details for a call with a number not associated with a contact. */
     public PhoneCallDetails(CharSequence number, int numberPresentation,
             CharSequence formattedNumber, String countryIso, String geocode,
-            int[] callTypes, long date, long duration, Drawable accountIcon) {
+            int[] callTypes, long date, long duration, Drawable accountIcon, int features,
+            Long dataUsage) {
         this(number, numberPresentation, formattedNumber, countryIso, geocode,
-                callTypes, date, duration, "", 0, "", null, null, 0, accountIcon);
+                callTypes, date, duration, "", 0, "", null, null, 0, accountIcon, features,
+                dataUsage);
     }
 
     /** Create the details for a call with a number associated with a contact. */
@@ -82,7 +92,7 @@
             CharSequence formattedNumber, String countryIso, String geocode,
             int[] callTypes, long date, long duration, CharSequence name,
             int numberType, CharSequence numberLabel, Uri contactUri,
-            Uri photoUri, int sourceType, Drawable accountIcon) {
+            Uri photoUri, int sourceType, Drawable accountIcon, int features, Long dataUsage) {
         this.number = number;
         this.numberPresentation = numberPresentation;
         this.formattedNumber = formattedNumber;
@@ -98,5 +108,7 @@
         this.photoUri = photoUri;
         this.sourceType = sourceType;
         this.accountIcon = accountIcon;
+        this.features = features;
+        this.dataUsage = dataUsage;
     }
 }
diff --git a/src/com/android/dialer/PhoneCallDetailsHelper.java b/src/com/android/dialer/PhoneCallDetailsHelper.java
index 62ef305..2a24557 100644
--- a/src/com/android/dialer/PhoneCallDetailsHelper.java
+++ b/src/com/android/dialer/PhoneCallDetailsHelper.java
@@ -17,6 +17,8 @@
 package com.android.dialer;
 
 import android.content.res.Resources;
+import android.provider.CallLog;
+import android.provider.CallLog.Calls;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
@@ -29,6 +31,7 @@
 import com.android.dialer.calllog.ContactInfo;
 import com.android.dialer.calllog.PhoneNumberDisplayHelper;
 import com.android.dialer.calllog.PhoneNumberUtilsWrapper;
+import com.android.dialer.util.DialerUtils;
 
 import com.google.common.collect.Lists;
 
@@ -77,6 +80,10 @@
         for (int index = 0; index < count && index < MAX_CALL_TYPE_ICONS; ++index) {
             views.callTypeIcons.add(details.callTypes[index]);
         }
+
+        // Show the video icon if the call had video enabled.
+        views.callTypeIcons.setShowVideo(
+                (details.features & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO);
         views.callTypeIcons.requestLayout();
         views.callTypeIcons.setVisibility(View.VISIBLE);
 
@@ -142,7 +149,7 @@
         mDescriptionItems.add(getCallDate(details));
 
         // Create a comma separated list from the call type or location, and call date.
-        return TextUtils.join(", " , mDescriptionItems);
+        return DialerUtils.join(mResources, mDescriptionItems);
     }
 
     /**
diff --git a/src/com/android/dialer/calllog/CallDetailHistoryAdapter.java b/src/com/android/dialer/calllog/CallDetailHistoryAdapter.java
index 67cadb1..cc116e7 100644
--- a/src/com/android/dialer/calllog/CallDetailHistoryAdapter.java
+++ b/src/com/android/dialer/calllog/CallDetailHistoryAdapter.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.provider.CallLog.Calls;
 import android.text.format.DateUtils;
+import android.text.format.Formatter;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -27,6 +28,10 @@
 
 import com.android.dialer.PhoneCallDetails;
 import com.android.dialer.R;
+import com.android.dialer.util.DialerUtils;
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
 
 /**
  * Adapter for a ListView containing history items from the details of a call.
@@ -42,6 +47,11 @@
     private final CallTypeHelper mCallTypeHelper;
     private final PhoneCallDetails[] mPhoneCallDetails;
 
+    /**
+     * List of items to be concatenated together for duration strings.
+     */
+    private ArrayList<CharSequence> mDurationItems = Lists.newArrayList();
+
     public CallDetailHistoryAdapter(Context context, LayoutInflater layoutInflater,
             CallTypeHelper callTypeHelper, PhoneCallDetails[] phoneCallDetails) {
         mContext = context;
@@ -114,6 +124,8 @@
         int callType = details.callTypes[0];
         callTypeIconView.clear();
         callTypeIconView.add(callType);
+        callTypeIconView.setShowVideo(
+                (details.features & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO);
         callTypeTextView.setText(mCallTypeHelper.getCallTypeText(callType));
         // Set the date.
         CharSequence dateValue = DateUtils.formatDateRange(mContext, details.date, details.date,
@@ -125,13 +137,13 @@
             durationView.setVisibility(View.GONE);
         } else {
             durationView.setVisibility(View.VISIBLE);
-            durationView.setText(formatDuration(details.duration));
+            durationView.setText(formatDurationAndDataUsage(details.duration, details.dataUsage));
         }
 
         return result;
     }
 
-    private String formatDuration(long elapsedSeconds) {
+    private CharSequence formatDuration(long elapsedSeconds) {
         long minutes = 0;
         long seconds = 0;
 
@@ -143,4 +155,25 @@
 
         return mContext.getString(R.string.callDetailsDurationFormat, minutes, seconds);
     }
+
+    /**
+     * Formats a string containing the call duration and the data usage (if specified).
+     *
+     * @param elapsedSeconds Total elapsed seconds.
+     * @param dataUsage Data usage in bytes, or null if not specified.
+     * @return String containing call duration and data usage.
+     */
+    private CharSequence formatDurationAndDataUsage(long elapsedSeconds, Long dataUsage) {
+        CharSequence duration = formatDuration(elapsedSeconds);
+
+        if (dataUsage != null) {
+            mDurationItems.clear();
+            mDurationItems.add(duration);
+            mDurationItems.add(Formatter.formatShortFileSize(mContext, dataUsage));
+
+            return DialerUtils.join(mContext.getResources(), mDurationItems);
+        } else {
+            return duration;
+        }
+    }
 }
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index 483c502..2987c9e 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -742,17 +742,23 @@
         final int[] callTypes = getCallTypes(c, count);
         final String geocode = c.getString(CallLogQuery.GEOCODED_LOCATION);
         final int sourceType = info.sourceType;
+        final int features = getCallFeatures(c, count);
+        Long dataUsage = null;
+        if (!c.isNull(CallLogQuery.DATA_USAGE)) {
+            dataUsage = c.getLong(CallLogQuery.DATA_USAGE);
+        }
+
         final PhoneCallDetails details;
 
         if (TextUtils.isEmpty(name)) {
             details = new PhoneCallDetails(number, numberPresentation,
                     formattedNumber, countryIso, geocode, callTypes, date,
-                    duration, accountIcon);
+                    duration, accountIcon, features, dataUsage);
         } else {
             details = new PhoneCallDetails(number, numberPresentation,
                     formattedNumber, countryIso, geocode, callTypes, date,
                     duration, name, ntype, label, lookupUri, photoUri, sourceType,
-                    accountIcon);
+                    accountIcon, features, dataUsage);
         }
 
         mCallLogViewsHelper.setPhoneCallDetails(views, details);
@@ -1182,6 +1188,25 @@
         return callTypes;
     }
 
+    /**
+     * Determine the features which were enabled for any of the calls that make up a call log
+     * entry.
+     *
+     * @param cursor The cursor.
+     * @param count The number of calls for the current call log entry.
+     * @return The features.
+     */
+    private int getCallFeatures(Cursor cursor, int count) {
+        int features = Calls.FEATURES_NONE;
+        int position = cursor.getPosition();
+        for (int index = 0; index < count; ++index) {
+            features |= cursor.getInt(CallLogQuery.FEATURES);
+            cursor.moveToNext();
+        }
+        cursor.moveToPosition(position);
+        return features;
+    }
+
     private PhoneAccount getAccount(Cursor c) {
         final String component_name = c.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME);
         final String account_id = c.getString(CallLogQuery.ACCOUNT_ID);
diff --git a/src/com/android/dialer/calllog/CallLogQuery.java b/src/com/android/dialer/calllog/CallLogQuery.java
index 8b88818..904ce74 100644
--- a/src/com/android/dialer/calllog/CallLogQuery.java
+++ b/src/com/android/dialer/calllog/CallLogQuery.java
@@ -46,6 +46,8 @@
             Calls.NUMBER_PRESENTATION,          // 17
             Calls.PHONE_ACCOUNT_COMPONENT_NAME, // 18
             Calls.PHONE_ACCOUNT_ID,             // 19
+            Calls.FEATURES,                     // 20
+            Calls.DATA_USAGE                    // 21
     };
 
     public static final int ID = 0;
@@ -68,4 +70,6 @@
     public static final int NUMBER_PRESENTATION = 17;
     public static final int ACCOUNT_COMPONENT_NAME = 18;
     public static final int ACCOUNT_ID = 19;
+    public static final int FEATURES = 20;
+    public static final int DATA_USAGE = 21;
 }
diff --git a/src/com/android/dialer/calllog/CallTypeIconsView.java b/src/com/android/dialer/calllog/CallTypeIconsView.java
index afbced4..382056c 100644
--- a/src/com/android/dialer/calllog/CallTypeIconsView.java
+++ b/src/com/android/dialer/calllog/CallTypeIconsView.java
@@ -17,8 +17,11 @@
 package com.android.dialer.calllog;
 
 import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.PorterDuff;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.provider.CallLog.Calls;
 import android.util.AttributeSet;
@@ -38,6 +41,7 @@
  */
 public class CallTypeIconsView extends View {
     private List<Integer> mCallTypes = Lists.newArrayListWithCapacity(3);
+    private boolean mShowVideo = false;
     private Resources mResources;
     private int mWidth;
     private int mHeight;
@@ -67,6 +71,20 @@
         invalidate();
     }
 
+    /**
+     * Determines whether the video call icon will be shown.
+     *
+     * @param showVideo True where the video icon should be shown.
+     */
+    public void setShowVideo(boolean showVideo) {
+        mShowVideo = showVideo;
+        if (showVideo) {
+            mWidth += mResources.videoCall.getIntrinsicWidth();
+            mHeight = Math.max(mHeight, mResources.videoCall.getIntrinsicHeight());
+            invalidate();
+        }
+    }
+
     @NeededForTesting
     public int getCount() {
         return mCallTypes.size();
@@ -111,6 +129,14 @@
             drawable.draw(canvas);
             left = right + mResources.iconMargin;
         }
+
+        // If showing the video call icon, draw it scaled appropriately.
+        if (mShowVideo) {
+            final Drawable drawable = mResources.videoCall;
+            final int right = left + mResources.videoCall.getIntrinsicWidth();
+            drawable.setBounds(left, 0, right, mResources.videoCall.getIntrinsicHeight());
+            drawable.draw(canvas);
+        }
     }
 
     private static class Resources {
@@ -136,6 +162,11 @@
         public final Drawable voicemail;
 
         /**
+         * Drawable repesenting a video call.
+         */
+        public final Drawable videoCall;
+
+        /**
          * The margin to use for icons.
          */
         public final int iconMargin;
@@ -163,6 +194,21 @@
             missed.setColorFilter(r.getColor(R.color.missed_call), PorterDuff.Mode.MULTIPLY);
 
             voicemail = r.getDrawable(R.drawable.ic_call_voicemail_holo_dark);
+
+            // Get the video call icon, scaled to match the height of the call arrows.
+            // We want the video call icon to be the same height as the call arrows, while keeping
+            // the same width aspect ratio.
+            Bitmap videoIcon = BitmapFactory.decodeResource(context.getResources(),
+                    R.drawable.ic_videocam_wht_24dp);
+            int scaledHeight = missed.getIntrinsicHeight();
+            int scaledWidth = (int) ((float) videoIcon.getWidth() *
+                    ((float) missed.getIntrinsicHeight() /
+                            (float) videoIcon.getHeight()));
+            Bitmap scaled = Bitmap.createScaledBitmap(videoIcon, scaledWidth, scaledHeight, false);
+            videoCall = new BitmapDrawable(context.getResources(), scaled);
+            videoCall.setColorFilter(r.getColor(R.color.dialtacts_secondary_text_color),
+                    PorterDuff.Mode.MULTIPLY);
+
             iconMargin = r.getDimensionPixelSize(R.dimen.call_log_icon_margin);
         }
     }
diff --git a/src/com/android/dialer/util/DialerUtils.java b/src/com/android/dialer/util/DialerUtils.java
index 484e97d..2b4a74c 100644
--- a/src/com/android/dialer/util/DialerUtils.java
+++ b/src/com/android/dialer/util/DialerUtils.java
@@ -24,6 +24,7 @@
 import android.content.res.Resources;
 import android.net.Uri;
 import android.provider.Telephony;
+import android.text.TextUtils;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -124,4 +125,17 @@
             }
         }
     }
+
+    /**
+     * Joins a list of {@link CharSequence} into a single {@link CharSequence} seperated by a
+     * localized delimiter such as ", ".
+     *
+     * @param resources Resources used to get list delimiter.
+     * @param list List of char sequences to join.
+     * @return Joined char sequences.
+     */
+    public static CharSequence join(Resources resources, Iterable<CharSequence> list) {
+        final CharSequence separator = resources.getString(R.string.list_delimeter);
+        return TextUtils.join(separator, list);
+    }
 }