• 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.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    */
CallLogListItemHelper( PhoneCallDetailsHelper phoneCallDetailsHelper, Resources resources, CallLogCache callLogCache)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
updatePhoneCallDetails(PhoneCallDetails details)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    */
setPhoneCallDetails(CallLogListItemViewHolder views, PhoneCallDetails details)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    */
setActionContentDescriptions(CallLogListItemViewHolder views)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    */
getContactBadgeDescription(PhoneCallDetails details)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    */
getCallDescription(PhoneCallDetails details)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    */
getCallDescriptionStringID(int[] callTypes, boolean isRead)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    */
getLastCallType(int[] callTypes)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    */
getNameOrNumber(PhoneCallDetails details)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