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