Details for multiple calls.

Add the details of the call at the bottom of the call details in a list.

The code allows having multiple details listed at the bottom, but
currently we only have one. A follow-up will add details for multiple
calls.

Change-Id: I0a91cc372f658bada603e22b9438a6db771dc124
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index d08b76a..ca17e7b 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.contacts;
 
+import com.android.contacts.calllog.CallDetailHistoryAdapter;
+import com.android.contacts.calllog.CallTypeHelper;
 import com.android.internal.telephony.CallerInfo;
 
 import android.app.ListActivity;
@@ -35,7 +37,6 @@
 import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.text.format.DateUtils;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -43,6 +44,7 @@
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.ImageView;
+import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -58,9 +60,8 @@
 
     /** The views representing the details of a phone call. */
     private PhoneCallDetailsViews mPhoneCallDetailsViews;
+    private CallTypeHelper mCallTypeHelper;
     private PhoneCallDetailsHelper mPhoneCallDetailsHelper;
-    private TextView mCallTimeView;
-    private TextView mCallDurationView;
     private View mHomeActionView;
     private ImageView mMainActionView;
     private ImageView mContactBackgroundView;
@@ -72,7 +73,6 @@
     /* package */ Resources mResources;
     /** Helper to load contact photos. */
     private ContactPhotoManager mContactPhotoManager;
-    /** Attached to the call action button in the UI. */
 
     static final String[] CALL_LOG_PROJECTION = new String[] {
         CallLog.Calls.DATE,
@@ -115,17 +115,16 @@
         mResources = getResources();
 
         mPhoneCallDetailsViews = PhoneCallDetailsViews.fromView(getWindow().getDecorView());
-        mPhoneCallDetailsHelper = new PhoneCallDetailsHelper(this, getResources(),
-                getVoicemailNumber(),
+        mCallTypeHelper = new CallTypeHelper(getResources(),
                 getResources().getDrawable(R.drawable.ic_call_log_list_incoming_call),
                 getResources().getDrawable(R.drawable.ic_call_log_list_outgoing_call),
                 getResources().getDrawable(R.drawable.ic_call_log_list_missed_call),
                 getResources().getDrawable(R.drawable.ic_call_log_list_voicemail));
+        mPhoneCallDetailsHelper = new PhoneCallDetailsHelper(this, getResources(),
+                getVoicemailNumber(), mCallTypeHelper);
         mHomeActionView = findViewById(R.id.action_bar_home);
         mMainActionView = (ImageView) findViewById(R.id.main_action);
         mContactBackgroundView = (ImageView) findViewById(R.id.contact_background);
-        mCallTimeView = (TextView) findViewById(R.id.time);
-        mCallDurationView = (TextView) findViewById(R.id.duration);
         mDefaultCountryIso = ContactsUtils.getCurrentCountryIso(this);
         mContactPhotoManager = ContactPhotoManager.getInstance(this);
         getListView().setOnItemClickListener(this);
@@ -183,19 +182,6 @@
                 if (TextUtils.isEmpty(countryIso)) {
                     countryIso = mDefaultCountryIso;
                 }
-                // Pull out string in format [relative], [date]
-                CharSequence dateClause = DateUtils.formatDateRange(this, date, date,
-                        DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE |
-                        DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_YEAR);
-                mCallTimeView.setText(dateClause);
-
-                // Set the duration
-                if (callType == Calls.MISSED_TYPE) {
-                    mCallDurationView.setVisibility(View.GONE);
-                } else {
-                    mCallDurationView.setVisibility(View.VISIBLE);
-                    mCallDurationView.setText(formatDuration(duration));
-                }
 
                 long photoId = 0L;
                 CharSequence nameText = "";
@@ -303,9 +289,14 @@
                     ViewAdapter adapter = new ViewAdapter(this, actions);
                     setListAdapter(adapter);
                 }
+                PhoneCallDetails details = new PhoneCallDetails(mNumber, numberText,
+                        new int[]{ callType }, duration, date, nameText, numberType, numberLabel);
                 mPhoneCallDetailsHelper.setPhoneCallDetails(mPhoneCallDetailsViews,
-                        new PhoneCallDetails(mNumber, numberText, new int[]{ callType }, date,
-                                nameText, numberType, numberLabel), false);
+                        details, false);
+                ListView historyList = (ListView) findViewById(R.id.history);
+                historyList.setAdapter(
+                        new CallDetailHistoryAdapter(this, mInflater, mCallTypeHelper,
+                                    new PhoneCallDetails[]{ details }));
 
                 loadContactPhotos(photoId);
             } else {
@@ -327,19 +318,6 @@
         mContactPhotoManager.loadPhoto(mContactBackgroundView, photoId);
     }
 
-    private String formatDuration(long elapsedSeconds) {
-        long minutes = 0;
-        long seconds = 0;
-
-        if (elapsedSeconds >= 60) {
-            minutes = elapsedSeconds / 60;
-            elapsedSeconds -= minutes * 60;
-        }
-        seconds = elapsedSeconds;
-
-        return getString(R.string.callDetailsDurationFormat, minutes, seconds);
-    }
-
     private String getVoicemailNumber() {
         TelephonyManager telephonyManager =
                 (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
diff --git a/src/com/android/contacts/PhoneCallDetails.java b/src/com/android/contacts/PhoneCallDetails.java
index 7b02a88..39620b2 100644
--- a/src/com/android/contacts/PhoneCallDetails.java
+++ b/src/com/android/contacts/PhoneCallDetails.java
@@ -35,6 +35,8 @@
     public final int[] callTypes;
     /** The date of the call, in milliseconds since the epoch. */
     public final long date;
+    /** The duration of the call in milliseconds, or 0 for missed calls. */
+    public final long duration;
     /** The name of the contact, or the empty string. */
     public final CharSequence name;
     /** The type of phone, e.g., {@link Phone#TYPE_HOME}, 0 if not available. */
@@ -44,17 +46,18 @@
 
     /** Create the details for a call with a number not associated with a contact. */
     public PhoneCallDetails(CharSequence number, CharSequence formattedNumber, int[] callTypes,
-            long date) {
-        this(number, formattedNumber, callTypes, date, "", 0, "");
+            long date, long duration) {
+        this(number, formattedNumber, callTypes, date, duration, "", 0, "");
     }
 
     /** Create the details for a call with a number associated with a contact. */
     public PhoneCallDetails(CharSequence number, CharSequence formattedNumber, int[] callTypes,
-            long date, CharSequence name, int numberType, CharSequence numberLabel) {
+            long date, long duration, CharSequence name, int numberType, CharSequence numberLabel) {
         this.number = number;
         this.formattedNumber = formattedNumber;
         this.callTypes = callTypes;
         this.date = date;
+        this.duration = duration;
         this.name = name;
         this.numberType = numberType;
         this.numberLabel = numberLabel;
diff --git a/src/com/android/contacts/PhoneCallDetailsHelper.java b/src/com/android/contacts/PhoneCallDetailsHelper.java
index 7f73b04..cbf3c5c 100644
--- a/src/com/android/contacts/PhoneCallDetailsHelper.java
+++ b/src/com/android/contacts/PhoneCallDetailsHelper.java
@@ -16,14 +16,13 @@
 
 package com.android.contacts;
 
+import com.android.contacts.calllog.CallTypeHelper;
 import com.android.contacts.format.FormatUtils;
 import com.android.internal.telephony.CallerInfo;
 
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.provider.CallLog.Calls;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.telephony.PhoneNumberUtils;
 import android.text.Spanned;
@@ -39,24 +38,9 @@
     private final Context mContext;
     private final Resources mResources;
     private final String mVoicemailNumber;
-    /** Icon for incoming calls. */
-    private final Drawable mIncomingDrawable;
-    /** Icon for outgoing calls. */
-    private final Drawable mOutgoingDrawable;
-    /** Icon for missed calls. */
-    private final Drawable mMissedDrawable;
-    /** Icon for voicemails. */
-    private final Drawable mVoicemailDrawable;
-    /** Name used to identify incoming calls. */
-    private final String mIncomingName;
-    /** Name used to identify outgoing calls. */
-    private final String mOutgoingName;
-    /** Name used to identify missed calls. */
-    private final String mMissedName;
-    /** Name used to identify voicemail calls. */
-    private final String mVoicemailName;
     /** The injected current time in milliseconds since the epoch. Used only by tests. */
     private Long mCurrentTimeMillisForTest;
+    private final CallTypeHelper mCallTypeHelper;
 
     /**
      * Creates a new instance of the helper.
@@ -66,20 +50,11 @@
      * @param resources used to look up strings
      */
     public PhoneCallDetailsHelper(Context context, Resources resources, String voicemailNumber,
-            Drawable incomingDrawable, Drawable outgoingDrawable, Drawable missedDrawable,
-            Drawable voicemailDrawable) {
+            CallTypeHelper callTypeHelper) {
         mContext = context;
         mResources = resources;
         mVoicemailNumber = voicemailNumber;
-        mIncomingDrawable = incomingDrawable;
-        mOutgoingDrawable = outgoingDrawable;
-        mMissedDrawable = missedDrawable;
-        mVoicemailDrawable = voicemailDrawable;
-        // Cache these values so that we do not need to look them up each time.
-        mIncomingName = mResources.getString(R.string.type_incoming);
-        mOutgoingName = mResources.getString(R.string.type_outgoing);
-        mMissedName = mResources.getString(R.string.type_missed);
-        mVoicemailName = mResources.getString(R.string.type_voicemail);
+        mCallTypeHelper = callTypeHelper;
     }
 
     /** Fills the call details views with content. */
@@ -90,7 +65,7 @@
             int count = details.callTypes.length;
             for (int callType : details.callTypes) {
                 ImageView callTypeImage = new ImageView(mContext);
-                callTypeImage.setImageDrawable(getCallTypeDrawable(callType));
+                callTypeImage.setImageDrawable(mCallTypeHelper.getCallTypeDrawable(callType));
                 views.callTypeIcons.addView(callTypeImage);
             }
             views.callTypeIcons.setVisibility(View.VISIBLE);
@@ -101,7 +76,7 @@
             // Use the name of the first call type.
             // TODO: We should update this to handle the text for multiple calls as well.
             int callType = details.callTypes[0];
-            views.callTypeText.setText(getCallTypeText(callType));
+            views.callTypeText.setText(mCallTypeHelper.getCallTypeText(callType));
             views.callTypeIcons.removeAllViews();
 
             views.callTypeText.setVisibility(View.VISIBLE);
@@ -155,46 +130,6 @@
         }
     }
 
-    /** Returns the text used to represent the given call type. */
-    private String getCallTypeText(int callType) {
-        switch (callType) {
-            case Calls.INCOMING_TYPE:
-                return mIncomingName;
-
-            case Calls.OUTGOING_TYPE:
-                return mOutgoingName;
-
-            case Calls.MISSED_TYPE:
-                return mMissedName;
-
-            case Calls.VOICEMAIL_TYPE:
-                return mVoicemailName;
-
-            default:
-                throw new IllegalArgumentException("invalid call type: " + callType);
-        }
-    }
-
-    /** Returns the drawable of the icon associated with the given call type. */
-    private Drawable getCallTypeDrawable(int callType) {
-        switch (callType) {
-            case Calls.INCOMING_TYPE:
-                return mIncomingDrawable;
-
-            case Calls.OUTGOING_TYPE:
-                return mOutgoingDrawable;
-
-            case Calls.MISSED_TYPE:
-                return mMissedDrawable;
-
-            case Calls.VOICEMAIL_TYPE:
-                return mVoicemailDrawable;
-
-            default:
-                throw new IllegalArgumentException("invalid call type: " + callType);
-        }
-    }
-
     private CharSequence getDisplayNumber(CharSequence number, CharSequence formattedNumber) {
         if (TextUtils.isEmpty(number)) {
             return "";
diff --git a/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java b/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
new file mode 100644
index 0000000..82ac971
--- /dev/null
+++ b/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 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.contacts.calllog;
+
+import com.android.contacts.PhoneCallDetails;
+import com.android.contacts.R;
+
+import android.content.Context;
+import android.provider.CallLog.Calls;
+import android.text.format.DateUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * Adapter for a ListView containing history items from the details of a call.
+ */
+public class CallDetailHistoryAdapter extends BaseAdapter {
+    private final Context mContext;
+    private final LayoutInflater mLayoutInflater;
+    private final CallTypeHelper mCallTypeHelper;
+    private final PhoneCallDetails[] mPhoneCallDetails;
+
+    public CallDetailHistoryAdapter(Context context, LayoutInflater layoutInflater,
+            CallTypeHelper callTypeHelper, PhoneCallDetails[] phoneCallDetails) {
+        mContext = context;
+        mLayoutInflater = layoutInflater;
+        mCallTypeHelper = callTypeHelper;
+        mPhoneCallDetails = phoneCallDetails;
+    }
+
+    @Override
+    public int getCount() {
+        return mPhoneCallDetails.length;
+    }
+
+    @Override
+    public Object getItem(int position) {
+        return mPhoneCallDetails[position];
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return position;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        // Make sure we have a valid convertView to start with
+        if (convertView == null) {
+            convertView = mLayoutInflater.inflate(R.layout.call_detail_history_item, parent, false);
+        }
+
+        PhoneCallDetails details = mPhoneCallDetails[position];
+        ImageView callTypeIconView = (ImageView) convertView.findViewById(R.id.call_type_icon);
+        TextView callTypeTextView = (TextView) convertView.findViewById(R.id.call_type_text);
+        TextView numberView = (TextView) convertView.findViewById(R.id.number);
+        TextView dateView = (TextView) convertView.findViewById(R.id.date);
+        TextView durationView = (TextView) convertView.findViewById(R.id.duration);
+
+        int callType = details.callTypes[0];
+        callTypeIconView.setImageDrawable(mCallTypeHelper.getCallTypeDrawable(callType));
+        callTypeTextView.setText(mCallTypeHelper.getCallTypeText(callType));
+        // TODO: Add the label for this number as well.
+        numberView.setText(details.number);
+        // Set the date.
+        CharSequence dateValue = DateUtils.formatDateRange(mContext, details.date, details.date,
+                DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE |
+                DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_YEAR);
+        dateView.setText(dateValue);
+        // Set the duration
+        if (callType == Calls.MISSED_TYPE) {
+            durationView.setVisibility(View.GONE);
+        } else {
+            durationView.setVisibility(View.VISIBLE);
+            durationView.setText(formatDuration(details.duration));
+        }
+
+        return convertView;
+    }
+
+    private String formatDuration(long elapsedSeconds) {
+        long minutes = 0;
+        long seconds = 0;
+
+        if (elapsedSeconds >= 60) {
+            minutes = elapsedSeconds / 60;
+            elapsedSeconds -= minutes * 60;
+        }
+        seconds = elapsedSeconds;
+
+        return mContext.getString(R.string.callDetailsDurationFormat, minutes, seconds);
+    }
+}
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index 11f8965..901ebd8 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -35,6 +35,7 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.database.CharArrayBuffer;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabaseCorruptException;
@@ -64,7 +65,6 @@
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.widget.AdapterView;
@@ -261,23 +261,25 @@
             mRequests = new LinkedList<CallerInfoQuery>();
             mPreDrawListener = null;
 
-            Drawable incomingDrawable = getResources().getDrawable(
+            Resources resources = getResources();
+            Drawable incomingDrawable = resources.getDrawable(
                     R.drawable.ic_call_log_list_incoming_call);
-            Drawable outgoingDrawable = getResources().getDrawable(
+            Drawable outgoingDrawable = resources.getDrawable(
                     R.drawable.ic_call_log_list_outgoing_call);
-            Drawable missedDrawable = getResources().getDrawable(
+            Drawable missedDrawable = resources.getDrawable(
                     R.drawable.ic_call_log_list_missed_call);
-            Drawable voicemailDrawable = getResources().getDrawable(
+            Drawable voicemailDrawable = resources.getDrawable(
                     R.drawable.ic_call_log_list_voicemail);
-            Drawable callDrawable = getResources().getDrawable(
+            Drawable callDrawable = resources.getDrawable(
                     R.drawable.ic_call_log_list_action_call);
-            Drawable playDrawable = getResources().getDrawable(
+            Drawable playDrawable = resources.getDrawable(
                     R.drawable.ic_call_log_list_action_play);
 
             mContactPhotoManager = ContactPhotoManager.getInstance(getActivity());
-            PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper(
-                    getActivity(), getResources(), mVoiceMailNumber, incomingDrawable,
+            CallTypeHelper callTypeHelper = new CallTypeHelper(resources, incomingDrawable,
                     outgoingDrawable, missedDrawable, voicemailDrawable);
+            PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper(
+                    getActivity(), resources, mVoiceMailNumber, callTypeHelper);
             mCallLogViewsHelper = new CallLogListItemHelper(phoneCallDetailsHelper, callDrawable,
                     playDrawable);
         }
@@ -640,6 +642,7 @@
 
             String number = c.getString(CallLogQuery.NUMBER);
             long date = c.getLong(CallLogQuery.DATE);
+            long duration = c.getLong(CallLogQuery.DURATION);
             final String formattedNumber;
             String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
             // Store away the number so we can call it directly if you click on the call icon
@@ -699,10 +702,10 @@
             int[] callTypes = getCallTypes(c, count);
             final PhoneCallDetails details;
             if (TextUtils.isEmpty(name)) {
-                details = new PhoneCallDetails(number, formattedNumber, callTypes, date);
+                details = new PhoneCallDetails(number, formattedNumber, callTypes, date, duration);
             } else {
-                details = new PhoneCallDetails(number, formattedNumber, callTypes, date, name,
-                        ntype, label);
+                details = new PhoneCallDetails(number, formattedNumber, callTypes, date, duration,
+                        name, ntype, label);
             }
             mCallLogViewsHelper.setPhoneCallDetails(views, details , true);
             if (views.photoView != null) {
diff --git a/src/com/android/contacts/calllog/CallTypeHelper.java b/src/com/android/contacts/calllog/CallTypeHelper.java
new file mode 100644
index 0000000..b06a1c1
--- /dev/null
+++ b/src/com/android/contacts/calllog/CallTypeHelper.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 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.contacts.calllog;
+
+import com.android.contacts.R;
+
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.provider.CallLog.Calls;
+
+/**
+ * Helper class to perform operations related to call types.
+ */
+public class CallTypeHelper {
+    /** Icon for incoming calls. */
+    private final Drawable mIncomingDrawable;
+    /** Icon for outgoing calls. */
+    private final Drawable mOutgoingDrawable;
+    /** Icon for missed calls. */
+    private final Drawable mMissedDrawable;
+    /** Icon for voicemails. */
+    private final Drawable mVoicemailDrawable;
+    /** Name used to identify incoming calls. */
+    private final String mIncomingName;
+    /** Name used to identify outgoing calls. */
+    private final String mOutgoingName;
+    /** Name used to identify missed calls. */
+    private final String mMissedName;
+    /** Name used to identify voicemail calls. */
+    private final String mVoicemailName;
+
+    public CallTypeHelper(Resources resources, Drawable incomingDrawable, Drawable outgoingDrawable,
+            Drawable missedDrawable, Drawable voicemailDrawable) {
+        mIncomingDrawable = incomingDrawable;
+        mOutgoingDrawable = outgoingDrawable;
+        mMissedDrawable = missedDrawable;
+        mVoicemailDrawable = voicemailDrawable;
+        // Cache these values so that we do not need to look them up each time.
+        mIncomingName = resources.getString(R.string.type_incoming);
+        mOutgoingName = resources.getString(R.string.type_outgoing);
+        mMissedName = resources.getString(R.string.type_missed);
+        mVoicemailName = resources.getString(R.string.type_voicemail);
+    }
+
+    /** Returns the text used to represent the given call type. */
+    public String getCallTypeText(int callType) {
+        switch (callType) {
+            case Calls.INCOMING_TYPE:
+                return mIncomingName;
+
+            case Calls.OUTGOING_TYPE:
+                return mOutgoingName;
+
+            case Calls.MISSED_TYPE:
+                return mMissedName;
+
+            case Calls.VOICEMAIL_TYPE:
+                return mVoicemailName;
+
+            default:
+                throw new IllegalArgumentException("invalid call type: " + callType);
+        }
+    }
+
+    /** Returns the drawable of the icon associated with the given call type. */
+    public Drawable getCallTypeDrawable(int callType) {
+        switch (callType) {
+            case Calls.INCOMING_TYPE:
+                return mIncomingDrawable;
+
+            case Calls.OUTGOING_TYPE:
+                return mOutgoingDrawable;
+
+            case Calls.MISSED_TYPE:
+                return mMissedDrawable;
+
+            case Calls.VOICEMAIL_TYPE:
+                return mVoicemailDrawable;
+
+            default:
+                throw new IllegalArgumentException("invalid call type: " + callType);
+        }
+    }
+}