PhoneCallDetailsHelper.java revision fb0a934ad90f1855787563eb80f2c8fff7f640ac
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.graphics.Typeface;
21import android.provider.ContactsContract;
22import android.provider.ContactsContract.CommonDataKinds.Phone;
23import android.telephony.PhoneNumberUtils;
24import android.text.SpannableString;
25import android.text.Spanned;
26import android.text.TextUtils;
27import android.text.format.DateUtils;
28import android.text.style.ForegroundColorSpan;
29import android.text.style.StyleSpan;
30import android.view.View;
31import android.widget.TextView;
32
33import com.android.contacts.common.test.NeededForTesting;
34import com.android.dialer.calllog.CallTypeHelper;
35import com.android.dialer.calllog.ContactInfo;
36import com.android.dialer.calllog.PhoneNumberHelper;
37import com.android.dialer.calllog.PhoneNumberUtilsWrapper;
38
39/**
40 * Helper class to fill in the views in {@link PhoneCallDetailsViews}.
41 */
42public class PhoneCallDetailsHelper {
43    /** The maximum number of icons will be shown to represent the call types in a group. */
44    private static final int MAX_CALL_TYPE_ICONS = 3;
45
46    private final Resources mResources;
47    /** The injected current time in milliseconds since the epoch. Used only by tests. */
48    private Long mCurrentTimeMillisForTest;
49    // Helper classes.
50    private final CallTypeHelper mCallTypeHelper;
51    private final PhoneNumberHelper mPhoneNumberHelper;
52    private final PhoneNumberUtilsWrapper mPhoneNumberUtilsWrapper;
53
54    /**
55     * Creates a new instance of the helper.
56     * <p>
57     * Generally you should have a single instance of this helper in any context.
58     *
59     * @param resources used to look up strings
60     */
61    public PhoneCallDetailsHelper(Resources resources, CallTypeHelper callTypeHelper,
62            PhoneNumberUtilsWrapper phoneUtils) {
63        mResources = resources;
64        mCallTypeHelper = callTypeHelper;
65        mPhoneNumberHelper = new PhoneNumberHelper(resources);
66        mPhoneNumberUtilsWrapper = phoneUtils;
67    }
68
69    /** Fills the call details views with content. */
70    public void setPhoneCallDetails(PhoneCallDetailsViews views, PhoneCallDetails details,
71            boolean isHighlighted) {
72        // Display up to a given number of icons.
73        views.callTypeIcons.clear();
74        int count = details.callTypes.length;
75        for (int index = 0; index < count && index < MAX_CALL_TYPE_ICONS; ++index) {
76            views.callTypeIcons.add(details.callTypes[index]);
77        }
78        views.callTypeIcons.requestLayout();
79        views.callTypeIcons.setVisibility(View.VISIBLE);
80
81        // Show the total call count only if there are more than the maximum number of icons.
82        final Integer callCount;
83        if (count > MAX_CALL_TYPE_ICONS) {
84            callCount = count;
85        } else {
86            callCount = null;
87        }
88        // The color to highlight the count and date in, if any. This is based on the first call.
89        Integer highlightColor =
90                isHighlighted ? mCallTypeHelper.getHighlightedColor(details.callTypes[0]) : null;
91
92        // The date of this call, relative to the current time.
93        CharSequence dateText =
94            DateUtils.getRelativeTimeSpanString(details.date,
95                    getCurrentTimeMillis(),
96                    DateUtils.MINUTE_IN_MILLIS,
97                    DateUtils.FORMAT_ABBREV_RELATIVE);
98
99        // Set the call count and date.
100        setCallCountAndDate(views, callCount, dateText, highlightColor);
101
102        CharSequence numberFormattedLabel = null;
103        // Only show a label if the number is shown and it is not a SIP address.
104        if (!TextUtils.isEmpty(details.number)
105                && !PhoneNumberUtils.isUriNumber(details.number.toString())) {
106            if (details.numberLabel == ContactInfo.GEOCODE_AS_LABEL) {
107                numberFormattedLabel = details.geocode;
108            } else {
109                numberFormattedLabel = Phone.getTypeLabel(mResources, details.numberType,
110                        details.numberLabel);
111            }
112        }
113
114        final CharSequence nameText;
115        final CharSequence numberText;
116        final CharSequence labelText;
117        final CharSequence displayNumber =
118            mPhoneNumberHelper.getDisplayNumber(details.number,
119                    details.numberPresentation, details.formattedNumber);
120        if (TextUtils.isEmpty(details.name)) {
121            nameText = displayNumber;
122            if (TextUtils.isEmpty(details.geocode)
123                    || mPhoneNumberUtilsWrapper.isVoicemailNumber(details.number)) {
124                numberText = mResources.getString(R.string.call_log_empty_gecode);
125            } else {
126                numberText = details.geocode;
127            }
128            labelText = numberText;
129            // We have a real phone number as "nameView" so make it always LTR
130            views.nameView.setTextDirection(View.TEXT_DIRECTION_LTR);
131        } else {
132            nameText = details.name;
133            numberText = displayNumber;
134            labelText = TextUtils.isEmpty(numberFormattedLabel) ? numberText :
135                    numberFormattedLabel;
136        }
137
138        views.nameView.setText(nameText);
139
140        views.labelView.setText(labelText);
141        views.labelView.setVisibility(TextUtils.isEmpty(labelText) ? View.GONE : View.VISIBLE);
142    }
143
144    /** Sets the text of the header view for the details page of a phone call. */
145    public void setCallDetailsHeader(TextView nameView, PhoneCallDetails details) {
146        final CharSequence nameText;
147        final CharSequence displayNumber =
148            mPhoneNumberHelper.getDisplayNumber(details.number, details.numberPresentation,
149                        mResources.getString(R.string.recentCalls_addToContact));
150        if (TextUtils.isEmpty(details.name)) {
151            nameText = displayNumber;
152        } else {
153            nameText = details.name;
154        }
155
156        nameView.setText(nameText);
157    }
158
159    @NeededForTesting
160    public void setCurrentTimeForTest(long currentTimeMillis) {
161        mCurrentTimeMillisForTest = currentTimeMillis;
162    }
163
164    /**
165     * Returns the current time in milliseconds since the epoch.
166     * <p>
167     * It can be injected in tests using {@link #setCurrentTimeForTest(long)}.
168     */
169    private long getCurrentTimeMillis() {
170        if (mCurrentTimeMillisForTest == null) {
171            return System.currentTimeMillis();
172        } else {
173            return mCurrentTimeMillisForTest;
174        }
175    }
176
177    /** Sets the call count and date. */
178    private void setCallCountAndDate(PhoneCallDetailsViews views, Integer callCount,
179            CharSequence dateText, Integer highlightColor) {
180        // Combine the count (if present) and the date.
181        final CharSequence text;
182        if (callCount != null) {
183            text = mResources.getString(
184                    R.string.call_log_item_count_and_date, callCount.intValue(), dateText);
185        } else {
186            text = dateText;
187        }
188
189        // Apply the highlight color if present.
190        final CharSequence formattedText;
191        if (highlightColor != null) {
192            formattedText = addBoldAndColor(text, highlightColor);
193        } else {
194            formattedText = text;
195        }
196
197        views.callTypeAndDate.setText(formattedText);
198    }
199
200    /** Creates a SpannableString for the given text which is bold and in the given color. */
201    private CharSequence addBoldAndColor(CharSequence text, int color) {
202        int flags = Spanned.SPAN_INCLUSIVE_INCLUSIVE;
203        SpannableString result = new SpannableString(text);
204        result.setSpan(new StyleSpan(Typeface.BOLD), 0, text.length(), flags);
205        result.setSpan(new ForegroundColorSpan(color), 0, text.length(), flags);
206        return result;
207    }
208}
209