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.calllog;
     18 
     19 import android.content.Context;
     20 import android.content.res.Resources;
     21 import android.provider.CallLog.Calls;
     22 import android.text.SpannableStringBuilder;
     23 import android.text.TextUtils;
     24 import android.util.Log;
     25 
     26 import com.android.dialer.PhoneCallDetails;
     27 import com.android.dialer.R;
     28 
     29 /**
     30  * Helper class to fill in the views of a call log entry.
     31  */
     32 /* package */class CallLogListItemHelper {
     33     private static final String TAG = "CallLogListItemHelper";
     34 
     35     /** Helper for populating the details of a phone call. */
     36     private final PhoneCallDetailsHelper mPhoneCallDetailsHelper;
     37     /** Resources to look up strings. */
     38     private final Resources mResources;
     39     private final TelecomCallLogCache mTelecomCallLogCache;
     40 
     41     /**
     42      * Creates a new helper instance.
     43      *
     44      * @param phoneCallDetailsHelper used to set the details of a phone call
     45      * @param phoneNumberHelper used to process phone number
     46      */
     47     public CallLogListItemHelper(
     48             PhoneCallDetailsHelper phoneCallDetailsHelper,
     49             Resources resources,
     50             TelecomCallLogCache telecomCallLogCache) {
     51         mPhoneCallDetailsHelper = phoneCallDetailsHelper;
     52         mResources = resources;
     53         mTelecomCallLogCache = telecomCallLogCache;
     54     }
     55 
     56     /**
     57      * Sets the name, label, and number for a contact.
     58      *
     59      * @param context The application context.
     60      * @param views the views to populate
     61      * @param details the details of a phone call needed to fill in the data
     62      */
     63     public void setPhoneCallDetails(
     64             CallLogListItemViewHolder views,
     65             PhoneCallDetails details) {
     66         mPhoneCallDetailsHelper.setPhoneCallDetails(views.phoneCallDetailsViews, details);
     67 
     68         // Set the accessibility text for the contact badge
     69         views.quickContactView.setContentDescription(getContactBadgeDescription(details));
     70 
     71         // Set the primary action accessibility description
     72         views.primaryActionView.setContentDescription(getCallDescription(details));
     73 
     74         // Cache name or number of caller.  Used when setting the content descriptions of buttons
     75         // when the actions ViewStub is inflated.
     76         views.nameOrNumber = getNameOrNumber(details);
     77     }
     78 
     79     /**
     80      * Sets the accessibility descriptions for the action buttons in the action button ViewStub.
     81      *
     82      * @param views The views associated with the current call log entry.
     83      */
     84     public void setActionContentDescriptions(CallLogListItemViewHolder views) {
     85         if (views.nameOrNumber == null) {
     86             Log.e(TAG, "setActionContentDescriptions; name or number is null.");
     87         }
     88 
     89         // Calling expandTemplate with a null parameter will cause a NullPointerException.
     90         // Although we don't expect a null name or number, it is best to protect against it.
     91         CharSequence nameOrNumber = views.nameOrNumber == null ? "" : views.nameOrNumber;
     92 
     93         views.videoCallButtonView.setContentDescription(
     94                 TextUtils.expandTemplate(
     95                         mResources.getString(R.string.description_video_call_action),
     96                         nameOrNumber));
     97 
     98         views.createNewContactButtonView.setContentDescription(
     99                 TextUtils.expandTemplate(
    100                         mResources.getString(R.string.description_create_new_contact_action),
    101                         nameOrNumber));
    102 
    103         views.addToExistingContactButtonView.setContentDescription(
    104                 TextUtils.expandTemplate(
    105                         mResources.getString(R.string.description_add_to_existing_contact_action),
    106                         nameOrNumber));
    107 
    108         views.detailsButtonView.setContentDescription(
    109                 TextUtils.expandTemplate(
    110                         mResources.getString(R.string.description_details_action), nameOrNumber));
    111     }
    112 
    113     /**
    114      * Returns the accessibility description for the contact badge for a call log entry.
    115      *
    116      * @param details Details of call.
    117      * @return Accessibility description.
    118      */
    119     private CharSequence getContactBadgeDescription(PhoneCallDetails details) {
    120         return mResources.getString(R.string.description_contact_details, getNameOrNumber(details));
    121     }
    122 
    123     /**
    124      * Returns the accessibility description of the "return call/call" action for a call log
    125      * entry.
    126      * Accessibility text is a combination of:
    127      * {Voicemail Prefix}. {Number of Calls}. {Caller information} {Phone Account}.
    128      * If most recent call is a voicemail, {Voicemail Prefix} is "New Voicemail.", otherwise "".
    129      *
    130      * If more than one call for the caller, {Number of Calls} is:
    131      * "{number of calls} calls.", otherwise "".
    132      *
    133      * The {Caller Information} references the most recent call associated with the caller.
    134      * For incoming calls:
    135      * If missed call:  Missed call from {Name/Number} {Call Type} {Call Time}.
    136      * If answered call: Answered call from {Name/Number} {Call Type} {Call Time}.
    137      *
    138      * For outgoing calls:
    139      * If outgoing:  Call to {Name/Number] {Call Type} {Call Time}.
    140      *
    141      * Where:
    142      * {Name/Number} is the name or number of the caller (as shown in call log).
    143      * {Call type} is the contact phone number type (eg mobile) or location.
    144      * {Call Time} is the time since the last call for the contact occurred.
    145      *
    146      * The {Phone Account} refers to the account/SIM through which the call was placed or received
    147      * in multi-SIM devices.
    148      *
    149      * Examples:
    150      * 3 calls.  New Voicemail.  Missed call from Joe Smith mobile 2 hours ago on SIM 1.
    151      *
    152      * 2 calls.  Answered call from John Doe mobile 1 hour ago.
    153      *
    154      * @param context The application context.
    155      * @param details Details of call.
    156      * @return Return call action description.
    157      */
    158     public CharSequence getCallDescription(PhoneCallDetails details) {
    159         int lastCallType = getLastCallType(details.callTypes);
    160         boolean isVoiceMail = lastCallType == Calls.VOICEMAIL_TYPE;
    161 
    162         // Get the name or number of the caller.
    163         final CharSequence nameOrNumber = getNameOrNumber(details);
    164 
    165         // Get the call type or location of the caller; null if not applicable
    166         final CharSequence typeOrLocation = mPhoneCallDetailsHelper.getCallTypeOrLocation(details);
    167 
    168         // Get the time/date of the call
    169         final CharSequence timeOfCall = mPhoneCallDetailsHelper.getCallDate(details);
    170 
    171         SpannableStringBuilder callDescription = new SpannableStringBuilder();
    172 
    173         // Prepend the voicemail indication.
    174         if (isVoiceMail) {
    175             callDescription.append(mResources.getString(R.string.description_new_voicemail));
    176         }
    177 
    178         // Add number of calls if more than one.
    179         if (details.callTypes.length > 1) {
    180             callDescription.append(mResources.getString(R.string.description_num_calls,
    181                     details.callTypes.length));
    182         }
    183 
    184         // If call had video capabilities, add the "Video Call" string.
    185         if ((details.features & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) {
    186             callDescription.append(mResources.getString(R.string.description_video_call));
    187         }
    188 
    189         int stringID = getCallDescriptionStringID(details.callTypes);
    190         String accountLabel = mTelecomCallLogCache.getAccountLabel(details.accountHandle);
    191 
    192         // Use chosen string resource to build up the message.
    193         CharSequence onAccountLabel = accountLabel == null
    194                 ? ""
    195                 : TextUtils.expandTemplate(
    196                         mResources.getString(R.string.description_phone_account),
    197                         accountLabel);
    198         callDescription.append(
    199                 TextUtils.expandTemplate(
    200                         mResources.getString(stringID),
    201                         nameOrNumber,
    202                         // If no type or location can be determined, sub in empty string.
    203                         typeOrLocation == null ? "" : typeOrLocation,
    204                         timeOfCall,
    205                         onAccountLabel));
    206 
    207         return callDescription;
    208     }
    209 
    210     /**
    211      * Determine the appropriate string ID to describe a call for accessibility purposes.
    212      *
    213      * @param details Call details.
    214      * @return String resource ID to use.
    215      */
    216     public int getCallDescriptionStringID(int[] callTypes) {
    217         int lastCallType = getLastCallType(callTypes);
    218         int stringID;
    219 
    220         if (lastCallType == Calls.VOICEMAIL_TYPE || lastCallType == Calls.MISSED_TYPE) {
    221             //Message: Missed call from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>,
    222             //<PhoneAccount>.
    223             stringID = R.string.description_incoming_missed_call;
    224         } else if (lastCallType == Calls.INCOMING_TYPE) {
    225             //Message: Answered call from <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>,
    226             //<PhoneAccount>.
    227             stringID = R.string.description_incoming_answered_call;
    228         } else {
    229             //Message: Call to <NameOrNumber>, <TypeOrLocation>, <TimeOfCall>, <PhoneAccount>.
    230             stringID = R.string.description_outgoing_call;
    231         }
    232         return stringID;
    233     }
    234 
    235     /**
    236      * Determine the call type for the most recent call.
    237      * @param callTypes Call types to check.
    238      * @return Call type.
    239      */
    240     private int getLastCallType(int[] callTypes) {
    241         if (callTypes.length > 0) {
    242             return callTypes[0];
    243         } else {
    244             return Calls.MISSED_TYPE;
    245         }
    246     }
    247 
    248     /**
    249      * Return the name or number of the caller specified by the details.
    250      * @param details Call details
    251      * @return the name (if known) of the caller, otherwise the formatted number.
    252      */
    253     private CharSequence getNameOrNumber(PhoneCallDetails details) {
    254         final CharSequence recipient;
    255         if (!TextUtils.isEmpty(details.name)) {
    256             recipient = details.name;
    257         } else {
    258             recipient = details.displayNumber;
    259         }
    260         return recipient;
    261     }
    262 }
    263