Home | History | Annotate | Download | only in calllog
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.dialer.app.calllog;
     18 
     19 import android.content.res.Resources;
     20 import android.provider.CallLog.Calls;
     21 import android.support.annotation.WorkerThread;
     22 import android.text.SpannableStringBuilder;
     23 import android.text.TextUtils;
     24 import com.android.dialer.app.R;
     25 import com.android.dialer.app.calllog.calllogcache.CallLogCache;
     26 import com.android.dialer.calllogutils.PhoneCallDetails;
     27 import com.android.dialer.common.Assert;
     28 import com.android.dialer.common.LogUtil;
     29 import com.android.dialer.compat.AppCompatConstants;
     30 
     31 /** Helper class to fill in the views of a call log entry. */
     32 /* package */ class CallLogListItemHelper {
     33 
     34   /** Helper for populating the details of a phone call. */
     35   private final PhoneCallDetailsHelper mPhoneCallDetailsHelper;
     36   /** Resources to look up strings. */
     37   private final Resources mResources;
     38 
     39   private final CallLogCache mCallLogCache;
     40 
     41   /**
     42    * Creates a new helper instance.
     43    *
     44    * @param phoneCallDetailsHelper used to set the details of a phone call
     45    * @param resources The object from which resources can be retrieved
     46    * @param callLogCache A cache for values retrieved from telecom/telephony
     47    */
     48   public CallLogListItemHelper(
     49       PhoneCallDetailsHelper phoneCallDetailsHelper,
     50       Resources resources,
     51       CallLogCache callLogCache) {
     52     mPhoneCallDetailsHelper = phoneCallDetailsHelper;
     53     mResources = resources;
     54     mCallLogCache = callLogCache;
     55   }
     56 
     57   /**
     58    * Update phone call details. This is called before any drawing to avoid expensive operation on UI
     59    * thread.
     60    *
     61    * @param details
     62    */
     63   @WorkerThread
     64   public void updatePhoneCallDetails(PhoneCallDetails details) {
     65     Assert.isWorkerThread();
     66     details.callLocationAndDate = mPhoneCallDetailsHelper.getCallLocationAndDate(details);
     67     details.callDescription = getCallDescription(details);
     68   }
     69 
     70   /**
     71    * Sets the name, label, and number for a contact.
     72    *
     73    * @param views the views to populate
     74    * @param details the details of a phone call needed to fill in the data
     75    */
     76   public void setPhoneCallDetails(CallLogListItemViewHolder views, PhoneCallDetails details) {
     77     mPhoneCallDetailsHelper.setPhoneCallDetails(views.phoneCallDetailsViews, details);
     78 
     79     // Set the accessibility text for the contact badge
     80     views.quickContactView.setContentDescription(getContactBadgeDescription(details));
     81 
     82     // Set the primary action accessibility description
     83     views.primaryActionView.setContentDescription(details.callDescription);
     84 
     85     // Cache name or number of caller.  Used when setting the content descriptions of buttons
     86     // when the actions ViewStub is inflated.
     87     views.nameOrNumber = getNameOrNumber(details);
     88 
     89     // The call type or Location associated with the call. Use when setting text for a
     90     // voicemail log's call button
     91     views.callTypeOrLocation = mPhoneCallDetailsHelper.getCallTypeOrLocation(details);
     92 
     93     // Cache country iso. Used for number filtering.
     94     views.countryIso = details.countryIso;
     95 
     96     views.updatePhoto();
     97   }
     98 
     99   /**
    100    * Sets the accessibility descriptions for the action buttons in the action button ViewStub.
    101    *
    102    * @param views The views associated with the current call log entry.
    103    */
    104   public void setActionContentDescriptions(CallLogListItemViewHolder views) {
    105     if (views.nameOrNumber == null) {
    106       LogUtil.e(
    107           "CallLogListItemHelper.setActionContentDescriptions",
    108           "setActionContentDescriptions; name or number is null.");
    109     }
    110 
    111     // Calling expandTemplate with a null parameter will cause a NullPointerException.
    112     // Although we don't expect a null name or number, it is best to protect against it.
    113     CharSequence nameOrNumber = views.nameOrNumber == null ? "" : views.nameOrNumber;
    114 
    115     views.videoCallButtonView.setContentDescription(
    116         TextUtils.expandTemplate(
    117             mResources.getString(R.string.description_video_call_action), nameOrNumber));
    118 
    119     views.createNewContactButtonView.setContentDescription(
    120         TextUtils.expandTemplate(
    121             mResources.getString(R.string.description_create_new_contact_action), nameOrNumber));
    122 
    123     views.addToExistingContactButtonView.setContentDescription(
    124         TextUtils.expandTemplate(
    125             mResources.getString(R.string.description_add_to_existing_contact_action),
    126             nameOrNumber));
    127 
    128     views.detailsButtonView.setContentDescription(
    129         TextUtils.expandTemplate(
    130             mResources.getString(R.string.description_details_action), nameOrNumber));
    131   }
    132 
    133   /**
    134    * Returns the accessibility description for the contact badge for a call log entry.
    135    *
    136    * @param details Details of call.
    137    * @return Accessibility description.
    138    */
    139   private CharSequence getContactBadgeDescription(PhoneCallDetails details) {
    140     if (details.isSpam) {
    141       return mResources.getString(
    142           R.string.description_spam_contact_details, getNameOrNumber(details));
    143     }
    144     return mResources.getString(R.string.description_contact_details, getNameOrNumber(details));
    145   }
    146 
    147   /**
    148    * Returns the accessibility description of the "return call/call" action for a call log entry.
    149    * Accessibility text is a combination of: {Voicemail Prefix}. {Number of Calls}. {Caller
    150    * information} {Phone Account}. If most recent call is a voicemail, {Voicemail Prefix} is "New
    151    * Voicemail.", otherwise "".
    152    *
    153    * <p>If more than one call for the caller, {Number of Calls} is: "{number of calls} calls.",
    154    * otherwise "".
    155    *
    156    * <p>The {Caller Information} references the most recent call associated with the caller. For
    157    * incoming calls: If missed call: Missed call from {Name/Number} {Call Type} {Call Time}. If
    158    * answered call: Answered call from {Name/Number} {Call Type} {Call Time}.
    159    *
    160    * <p>For outgoing calls: If outgoing: Call to {Name/Number] {Call Type} {Call Time}.
    161    *
    162    * <p>Where: {Name/Number} is the name or number of the caller (as shown in call log). {Call type}
    163    * is the contact phone number type (eg mobile) or location. {Call Time} is the time since the
    164    * last call for the contact occurred.
    165    *
    166    * <p>The {Phone Account} refers to the account/SIM through which the call was placed or received
    167    * in multi-SIM devices.
    168    *
    169    * <p>Examples: 3 calls. New Voicemail. Missed call from Joe Smith mobile 2 hours ago on SIM 1.
    170    *
    171    * <p>2 calls. Answered call from John Doe mobile 1 hour ago.
    172    *
    173    * @param details Details of call.
    174    * @return Return call action description.
    175    */
    176   public CharSequence getCallDescription(PhoneCallDetails details) {
    177     // Get the name or number of the caller.
    178     final CharSequence nameOrNumber = getNameOrNumber(details);
    179 
    180     // Get the call type or location of the caller; null if not applicable
    181     final CharSequence typeOrLocation = mPhoneCallDetailsHelper.getCallTypeOrLocation(details);
    182 
    183     // Get the time/date of the call
    184     final CharSequence timeOfCall = mPhoneCallDetailsHelper.getCallDate(details);
    185 
    186     SpannableStringBuilder callDescription = new SpannableStringBuilder();
    187 
    188     // Add number of calls if more than one.
    189     if (details.callTypes.length > 1) {
    190       callDescription.append(
    191           mResources.getString(R.string.description_num_calls, details.callTypes.length));
    192     }
    193 
    194     // If call had video capabilities, add the "Video Call" string.
    195     if ((details.features & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) {
    196       callDescription.append(mResources.getString(R.string.description_video_call));
    197     }
    198 
    199     String accountLabel = mCallLogCache.getAccountLabel(details.accountHandle);
    200     CharSequence onAccountLabel =
    201         PhoneCallDetails.createAccountLabelDescription(mResources, details.viaNumber, accountLabel);
    202 
    203     int stringID = getCallDescriptionStringID(details.callTypes, details.isRead);
    204     callDescription.append(
    205         TextUtils.expandTemplate(
    206             mResources.getString(stringID),
    207             nameOrNumber,
    208             typeOrLocation == null ? "" : typeOrLocation,
    209             timeOfCall,
    210             onAccountLabel));
    211 
    212     return callDescription;
    213   }
    214 
    215   /**
    216    * Determine the appropriate string ID to describe a call for accessibility purposes.
    217    *
    218    * @param callTypes The type of call corresponding to this entry or multiple if this entry
    219    *     represents multiple calls grouped together.
    220    * @param isRead If the entry is a voicemail, {@code true} if the voicemail is read.
    221    * @return String resource ID to use.
    222    */
    223   public int getCallDescriptionStringID(int[] callTypes, boolean isRead) {
    224     int lastCallType = getLastCallType(callTypes);
    225     int stringID;
    226 
    227     if (lastCallType == AppCompatConstants.CALLS_MISSED_TYPE) {
    228       //Message: Missed call from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>,
    229       //<PhoneAccount>.
    230       stringID = R.string.description_incoming_missed_call;
    231     } else if (lastCallType == AppCompatConstants.CALLS_INCOMING_TYPE) {
    232       //Message: Answered call from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>,
    233       //<PhoneAccount>.
    234       stringID = R.string.description_incoming_answered_call;
    235     } else if (lastCallType == AppCompatConstants.CALLS_VOICEMAIL_TYPE) {
    236       //Message: (Unread) [V/v]oicemail from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>,
    237       //<PhoneAccount>.
    238       stringID =
    239           isRead ? R.string.description_read_voicemail : R.string.description_unread_voicemail;
    240     } else {
    241       //Message: Call to <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>, <PhoneAccount>.
    242       stringID = R.string.description_outgoing_call;
    243     }
    244     return stringID;
    245   }
    246 
    247   /**
    248    * Determine the call type for the most recent call.
    249    *
    250    * @param callTypes Call types to check.
    251    * @return Call type.
    252    */
    253   private int getLastCallType(int[] callTypes) {
    254     if (callTypes.length > 0) {
    255       return callTypes[0];
    256     } else {
    257       return Calls.MISSED_TYPE;
    258     }
    259   }
    260 
    261   /**
    262    * Return the name or number of the caller specified by the details.
    263    *
    264    * @param details Call details
    265    * @return the name (if known) of the caller, otherwise the formatted number.
    266    */
    267   private CharSequence getNameOrNumber(PhoneCallDetails details) {
    268     final CharSequence recipient;
    269     if (!TextUtils.isEmpty(details.getPreferredName())) {
    270       recipient = details.getPreferredName();
    271     } else {
    272       recipient = details.displayNumber;
    273     }
    274     return recipient;
    275   }
    276 }
    277