1/*
2 * Copyright (C) 2014 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 */
16package com.android.contacts.interactions;
17
18import android.content.ContentValues;
19import android.content.Context;
20import android.content.Intent;
21import android.content.res.Resources;
22import android.graphics.PorterDuff;
23import android.graphics.drawable.Drawable;
24import android.net.Uri;
25import android.provider.CallLog.Calls;
26import android.provider.ContactsContract.CommonDataKinds.Phone;
27import android.text.BidiFormatter;
28import android.text.Spannable;
29import android.text.TextDirectionHeuristics;
30
31import com.android.contacts.GeoUtil;
32import com.android.contacts.R;
33import com.android.contacts.compat.PhoneNumberUtilsCompat;
34import com.android.contacts.util.BitmapUtil;
35import com.android.contacts.util.ContactDisplayUtils;
36
37/**
38 * Represents a call log event interaction, wrapping the columns in
39 * {@link android.provider.CallLog.Calls}.
40 *
41 * This class does not return log entries related to voicemail or SIP calls. Additionally,
42 * this class ignores number presentation. Number presentation affects how to identify phone
43 * numbers. Since, we already know the identity of the phone number owner we can ignore number
44 * presentation.
45 *
46 * As a result of ignoring voicemail and number presentation, we don't need to worry about API
47 * version.
48 */
49public class CallLogInteraction implements ContactInteraction {
50
51    private static final String URI_TARGET_PREFIX = "tel:";
52    private static final int CALL_LOG_ICON_RES = R.drawable.quantum_ic_phone_vd_theme_24;
53    private static final int CALL_ARROW_ICON_RES = R.drawable.ic_call_arrow;
54    private static BidiFormatter sBidiFormatter = BidiFormatter.getInstance();
55
56    private ContentValues mValues;
57
58    public CallLogInteraction(ContentValues values) {
59        mValues = values;
60    }
61
62    @Override
63    public Intent getIntent() {
64        String number = getNumber();
65        return number == null ? null : new Intent(Intent.ACTION_CALL).setData(
66                Uri.parse(URI_TARGET_PREFIX + number));
67    }
68
69    @Override
70    public String getViewHeader(Context context) {
71        String number = mValues.getAsString(Calls.NUMBER);
72        if (number != null) {
73            number = PhoneNumberUtilsCompat.formatNumber(number,
74                    PhoneNumberUtilsCompat.normalizeNumber(number),
75                    GeoUtil.getCurrentCountryIso(context));
76            return sBidiFormatter.unicodeWrap(number, TextDirectionHeuristics.LTR);
77        }
78        return null;
79    }
80
81    @Override
82    public long getInteractionDate() {
83        Long date = getDate();
84        return date == null ? -1 : date;
85    }
86
87    @Override
88    public String getViewBody(Context context) {
89        Integer numberType = getCachedNumberType();
90        if (numberType == null) {
91            return null;
92        }
93        return Phone.getTypeLabel(context.getResources(), getCachedNumberType(),
94                getCachedNumberLabel()).toString();
95    }
96
97    @Override
98    public String getViewFooter(Context context) {
99        final Long date = getDate();
100        if (date != null) {
101            final StringBuilder callDetail = new StringBuilder();
102            callDetail.append(ContactInteractionUtil.formatDateStringFromTimestamp(date, context));
103            final Long duration = getDuration();
104            if (duration != null) {
105                callDetail.append("\n");
106                callDetail.append(ContactInteractionUtil.formatDuration(duration, context));
107            }
108            return callDetail.toString();
109        }
110        return null;
111    }
112
113    @Override
114    public Drawable getIcon(Context context) {
115        return context.getResources().getDrawable(CALL_LOG_ICON_RES);
116    }
117
118    @Override
119    public Drawable getBodyIcon(Context context) {
120        return null;
121    }
122
123    @Override
124    public Drawable getFooterIcon(Context context) {
125        Drawable callArrow = null;
126        Resources res = context.getResources();
127        Integer type = getType();
128        if (type == null) {
129            return null;
130        }
131        switch (type) {
132            case Calls.INCOMING_TYPE:
133                callArrow = res.getDrawable(CALL_ARROW_ICON_RES);
134                callArrow.mutate().setColorFilter(res.getColor(R.color.call_arrow_green),
135                        PorterDuff.Mode.MULTIPLY);
136                break;
137            case Calls.MISSED_TYPE:
138                callArrow = res.getDrawable(CALL_ARROW_ICON_RES);
139                callArrow.mutate().setColorFilter(res.getColor(R.color.call_arrow_red),
140                        PorterDuff.Mode.MULTIPLY);
141                break;
142            case Calls.OUTGOING_TYPE:
143                callArrow = BitmapUtil.getRotatedDrawable(res, CALL_ARROW_ICON_RES, 180f);
144                callArrow.setColorFilter(res.getColor(R.color.call_arrow_green),
145                        PorterDuff.Mode.MULTIPLY);
146                break;
147        }
148        return callArrow;
149    }
150
151    public String getCachedName() {
152        return mValues.getAsString(Calls.CACHED_NAME);
153    }
154
155    public String getCachedNumberLabel() {
156        return mValues.getAsString(Calls.CACHED_NUMBER_LABEL);
157    }
158
159    public Integer getCachedNumberType() {
160        return mValues.getAsInteger(Calls.CACHED_NUMBER_TYPE);
161    }
162
163    public Long getDate() {
164        return mValues.getAsLong(Calls.DATE);
165    }
166
167    public Long getDuration() {
168        return mValues.getAsLong(Calls.DURATION);
169    }
170
171    public Boolean getIsRead() {
172        return mValues.getAsBoolean(Calls.IS_READ);
173    }
174
175    public Integer getLimitParamKey() {
176        return mValues.getAsInteger(Calls.LIMIT_PARAM_KEY);
177    }
178
179    public Boolean getNew() {
180        return mValues.getAsBoolean(Calls.NEW);
181    }
182
183    public String getNumber() {
184        final String number = mValues.getAsString(Calls.NUMBER);
185        return number == null ? null :
186            sBidiFormatter.unicodeWrap(number, TextDirectionHeuristics.LTR);
187    }
188
189    public Integer getNumberPresentation() {
190        return mValues.getAsInteger(Calls.NUMBER_PRESENTATION);
191    }
192
193    public Integer getOffsetParamKey() {
194        return mValues.getAsInteger(Calls.OFFSET_PARAM_KEY);
195    }
196
197    public Integer getType() {
198        return mValues.getAsInteger(Calls.TYPE);
199    }
200
201    @Override
202    public Spannable getContentDescription(Context context) {
203        final String phoneNumber = getViewHeader(context);
204        final String contentDescription = context.getResources().getString(
205                R.string.content_description_recent_call,
206                getCallTypeString(context), phoneNumber, getViewFooter(context));
207        return ContactDisplayUtils.getTelephoneTtsSpannable(contentDescription, phoneNumber);
208    }
209
210    private String getCallTypeString(Context context) {
211        String callType = "";
212        Resources res = context.getResources();
213        Integer type = getType();
214        if (type == null) {
215            return callType;
216        }
217        switch (type) {
218            case Calls.INCOMING_TYPE:
219                callType = res.getString(R.string.content_description_recent_call_type_incoming);
220                break;
221            case Calls.MISSED_TYPE:
222                callType = res.getString(R.string.content_description_recent_call_type_missed);
223                break;
224            case Calls.OUTGOING_TYPE:
225                callType = res.getString(R.string.content_description_recent_call_type_outgoing);
226                break;
227        }
228        return callType;
229    }
230
231    @Override
232    public int getIconResourceId() {
233        return CALL_LOG_ICON_RES;
234    }
235}
236