PhoneCallDetailsHelper.java revision 8cd9423bd04584acbcbf178bf6a1c1953debb8da
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
17package com.android.dialer;
18
19import android.content.res.Resources;
20import android.provider.CallLog;
21import android.provider.CallLog.Calls;
22import android.provider.ContactsContract.CommonDataKinds.Phone;
23import android.text.TextUtils;
24import android.text.format.DateUtils;
25import android.view.View;
26import android.widget.TextView;
27
28import com.android.contacts.common.testing.NeededForTesting;
29import com.android.contacts.common.util.PhoneNumberHelper;
30import com.android.dialer.calllog.CallTypeHelper;
31import com.android.dialer.calllog.ContactInfo;
32import com.android.dialer.calllog.PhoneNumberDisplayHelper;
33import com.android.dialer.calllog.PhoneNumberUtilsWrapper;
34import com.android.dialer.util.DialerUtils;
35
36import com.google.common.collect.Lists;
37
38import java.util.ArrayList;
39
40/**
41 * Helper class to fill in the views in {@link PhoneCallDetailsViews}.
42 */
43public class PhoneCallDetailsHelper {
44    /** The maximum number of icons will be shown to represent the call types in a group. */
45    private static final int MAX_CALL_TYPE_ICONS = 3;
46
47    private final Resources mResources;
48    /** The injected current time in milliseconds since the epoch. Used only by tests. */
49    private Long mCurrentTimeMillisForTest;
50    // Helper classes.
51    private final CallTypeHelper mCallTypeHelper;
52    private final PhoneNumberDisplayHelper mPhoneNumberHelper;
53    private final PhoneNumberUtilsWrapper mPhoneNumberUtilsWrapper;
54
55    /**
56     * List of items to be concatenated together for accessibility descriptions
57     */
58    private ArrayList<CharSequence> mDescriptionItems = Lists.newArrayList();
59
60    /**
61     * Creates a new instance of the helper.
62     * <p>
63     * Generally you should have a single instance of this helper in any context.
64     *
65     * @param resources used to look up strings
66     */
67    public PhoneCallDetailsHelper(Resources resources, CallTypeHelper callTypeHelper,
68            PhoneNumberUtilsWrapper phoneUtils) {
69        mResources = resources;
70        mCallTypeHelper = callTypeHelper;
71        mPhoneNumberUtilsWrapper = phoneUtils;
72        mPhoneNumberHelper = new PhoneNumberDisplayHelper(mPhoneNumberUtilsWrapper, resources);
73    }
74
75    /** Fills the call details views with content. */
76    public void setPhoneCallDetails(PhoneCallDetailsViews views, PhoneCallDetails details) {
77        // Display up to a given number of icons.
78        views.callTypeIcons.clear();
79        int count = details.callTypes.length;
80        boolean isVoicemail = false;
81        for (int index = 0; index < count && index < MAX_CALL_TYPE_ICONS; ++index) {
82            views.callTypeIcons.add(details.callTypes[index]);
83            if (index == 0) {
84                isVoicemail = details.callTypes[index] == Calls.VOICEMAIL_TYPE;
85            }
86        }
87
88        // Show the video icon if the call had video enabled.
89        views.callTypeIcons.setShowVideo(
90                (details.features & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO);
91        views.callTypeIcons.requestLayout();
92        views.callTypeIcons.setVisibility(View.VISIBLE);
93
94        // Show the total call count only if there are more than the maximum number of icons.
95        final Integer callCount;
96        if (count > MAX_CALL_TYPE_ICONS) {
97            callCount = count;
98        } else {
99            callCount = null;
100        }
101
102        CharSequence callLocationAndDate = getCallLocationAndDate(details);
103
104        // Set the call count, location and date.
105        setCallCountAndDate(views, callCount, callLocationAndDate);
106
107        // set the account icon if it exists
108        if (details.accountIcon != null) {
109            views.callAccountIcon.setVisibility(View.VISIBLE);
110            views.callAccountIcon.setImageDrawable(details.accountIcon);
111        } else {
112            views.callAccountIcon.setVisibility(View.GONE);
113        }
114
115        final CharSequence nameText;
116        final CharSequence displayNumber =
117            mPhoneNumberHelper.getDisplayNumber(details.number,
118                    details.numberPresentation, details.formattedNumber);
119        if (TextUtils.isEmpty(details.name)) {
120            nameText = displayNumber;
121            // We have a real phone number as "nameView" so make it always LTR
122            views.nameView.setTextDirection(View.TEXT_DIRECTION_LTR);
123        } else {
124            nameText = details.name;
125        }
126
127        views.nameView.setText(nameText);
128
129        if (isVoicemail && !TextUtils.isEmpty(details.transcription)) {
130            views.voicemailTranscriptionView.setText(details.transcription);
131            views.voicemailTranscriptionView.setVisibility(View.VISIBLE);
132        } else {
133            views.voicemailTranscriptionView.setText(null);
134            views.voicemailTranscriptionView.setVisibility(View.GONE);
135        }
136    }
137
138    /**
139     * Builds a string containing the call location and date.
140     *
141     * @param details The call details.
142     * @return The call location and date string.
143     */
144    private CharSequence getCallLocationAndDate(PhoneCallDetails details) {
145        mDescriptionItems.clear();
146
147        // Get type of call (ie mobile, home, etc) if known, or the caller's location.
148        CharSequence callTypeOrLocation = getCallTypeOrLocation(details);
149
150        // Only add the call type or location if its not empty.  It will be empty for unknown
151        // callers.
152        if (!TextUtils.isEmpty(callTypeOrLocation)) {
153            mDescriptionItems.add(callTypeOrLocation);
154        }
155        // The date of this call, relative to the current time.
156        mDescriptionItems.add(getCallDate(details));
157
158        // Create a comma separated list from the call type or location, and call date.
159        return DialerUtils.join(mResources, mDescriptionItems);
160    }
161
162    /**
163     * For a call, if there is an associated contact for the caller, return the known call type
164     * (e.g. mobile, home, work).  If there is no associated contact, attempt to use the caller's
165     * location if known.
166     * @param details Call details to use.
167     * @return Type of call (mobile/home) if known, or the location of the caller (if known).
168     */
169    public CharSequence getCallTypeOrLocation(PhoneCallDetails details) {
170        CharSequence numberFormattedLabel = null;
171        // Only show a label if the number is shown and it is not a SIP address.
172        if (!TextUtils.isEmpty(details.number)
173                && !PhoneNumberHelper.isUriNumber(details.number.toString())
174                && !mPhoneNumberUtilsWrapper.isVoicemailNumber(details.number)) {
175
176            if (details.numberLabel == ContactInfo.GEOCODE_AS_LABEL) {
177                numberFormattedLabel = details.geocode;
178            } else {
179                numberFormattedLabel = Phone.getTypeLabel(mResources, details.numberType,
180                        details.numberLabel);
181            }
182        }
183
184        if (!TextUtils.isEmpty(details.name) && TextUtils.isEmpty(numberFormattedLabel)) {
185            numberFormattedLabel = mPhoneNumberHelper.getDisplayNumber(details.number,
186                    details.numberPresentation, details.formattedNumber);
187        }
188        return numberFormattedLabel;
189    }
190
191    /**
192     * Get the call date/time of the call, relative to the current time.
193     * e.g. 3 minutes ago
194     * @param details Call details to use.
195     * @return String representing when the call occurred.
196     */
197    public CharSequence getCallDate(PhoneCallDetails details) {
198        return DateUtils.getRelativeTimeSpanString(details.date,
199                getCurrentTimeMillis(),
200                DateUtils.MINUTE_IN_MILLIS,
201                DateUtils.FORMAT_ABBREV_RELATIVE);
202    }
203
204    /** Sets the text of the header view for the details page of a phone call. */
205    @NeededForTesting
206    public void setCallDetailsHeader(TextView nameView, PhoneCallDetails details) {
207        final CharSequence nameText;
208        final CharSequence displayNumber =
209            mPhoneNumberHelper.getDisplayNumber(details.number, details.numberPresentation,
210                        mResources.getString(R.string.recentCalls_addToContact));
211        if (TextUtils.isEmpty(details.name)) {
212            nameText = displayNumber;
213        } else {
214            nameText = details.name;
215        }
216
217        nameView.setText(nameText);
218    }
219
220    @NeededForTesting
221    public void setCurrentTimeForTest(long currentTimeMillis) {
222        mCurrentTimeMillisForTest = currentTimeMillis;
223    }
224
225    /**
226     * Returns the current time in milliseconds since the epoch.
227     * <p>
228     * It can be injected in tests using {@link #setCurrentTimeForTest(long)}.
229     */
230    private long getCurrentTimeMillis() {
231        if (mCurrentTimeMillisForTest == null) {
232            return System.currentTimeMillis();
233        } else {
234            return mCurrentTimeMillisForTest;
235        }
236    }
237
238    /** Sets the call count and date. */
239    private void setCallCountAndDate(PhoneCallDetailsViews views, Integer callCount,
240            CharSequence dateText) {
241        // Combine the count (if present) and the date.
242        final CharSequence text;
243        if (callCount != null) {
244            text = mResources.getString(
245                    R.string.call_log_item_count_and_date, callCount.intValue(), dateText);
246        } else {
247            text = dateText;
248        }
249
250        views.callLocationAndDate.setText(text);
251    }
252}
253