1 /*
2  * Copyright (C) 2017 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.calldetails;
18 
19 import android.content.Context;
20 import android.net.Uri;
21 import android.provider.CallLog.Calls;
22 import android.support.annotation.ColorInt;
23 import android.support.annotation.NonNull;
24 import android.support.v4.content.ContextCompat;
25 import android.support.v7.widget.RecyclerView.ViewHolder;
26 import android.text.TextUtils;
27 import android.view.View;
28 import android.widget.ImageView;
29 import android.widget.TextView;
30 import com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry;
31 import com.android.dialer.calllogutils.CallEntryFormatter;
32 import com.android.dialer.calllogutils.CallTypeHelper;
33 import com.android.dialer.calllogutils.CallTypeIconsView;
34 import com.android.dialer.common.LogUtil;
35 import com.android.dialer.compat.AppCompatConstants;
36 import com.android.dialer.enrichedcall.historyquery.proto.HistoryResult;
37 import com.android.dialer.enrichedcall.historyquery.proto.HistoryResult.Type;
38 import com.android.dialer.oem.MotorolaUtils;
39 import com.android.dialer.util.CallUtil;
40 import com.android.dialer.util.DialerUtils;
41 import com.android.dialer.util.IntentUtil;
42 
43 /** ViewHolder for call entries in {@link CallDetailsActivity}. */
44 public class CallDetailsEntryViewHolder extends ViewHolder {
45 
46   private final CallTypeIconsView callTypeIcon;
47   private final TextView callTypeText;
48   private final TextView callTime;
49   private final TextView callDuration;
50 
51   private final View multimediaImageContainer;
52   private final View multimediaDetailsContainer;
53   private final View multimediaDivider;
54 
55   private final TextView multimediaDetails;
56   private final TextView postCallNote;
57 
58   private final ImageView multimediaImage;
59 
60   // TODO: Display this when location is stored - b/36160042
61   @SuppressWarnings("unused")
62   private final TextView multimediaAttachmentsNumber;
63 
64   private final Context context;
65 
CallDetailsEntryViewHolder(View container)66   public CallDetailsEntryViewHolder(View container) {
67     super(container);
68     context = container.getContext();
69 
70     callTypeIcon = (CallTypeIconsView) container.findViewById(R.id.call_direction);
71     callTypeText = (TextView) container.findViewById(R.id.call_type);
72     callTime = (TextView) container.findViewById(R.id.call_time);
73     callDuration = (TextView) container.findViewById(R.id.call_duration);
74 
75     multimediaImageContainer = container.findViewById(R.id.multimedia_image_container);
76     multimediaDetailsContainer = container.findViewById(R.id.ec_container);
77     multimediaDivider = container.findViewById(R.id.divider);
78     multimediaDetails = (TextView) container.findViewById(R.id.multimedia_details);
79     postCallNote = (TextView) container.findViewById(R.id.post_call_note);
80     multimediaImage = (ImageView) container.findViewById(R.id.multimedia_image);
81     multimediaAttachmentsNumber =
82         (TextView) container.findViewById(R.id.multimedia_attachments_number);
83   }
84 
setCallDetails( String number, CallDetailsEntry entry, CallTypeHelper callTypeHelper, boolean showMultimediaDivider)85   void setCallDetails(
86       String number,
87       CallDetailsEntry entry,
88       CallTypeHelper callTypeHelper,
89       boolean showMultimediaDivider) {
90     int callType = entry.getCallType();
91     boolean isVideoCall =
92         (entry.getFeatures() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO
93             && CallUtil.isVideoEnabled(context);
94     boolean isPulledCall =
95         (entry.getFeatures() & Calls.FEATURES_PULLED_EXTERNALLY)
96             == Calls.FEATURES_PULLED_EXTERNALLY;
97 
98     callTime.setTextColor(getColorForCallType(context, callType));
99     callTypeIcon.clear();
100     callTypeIcon.add(callType);
101     callTypeIcon.setShowVideo((entry.getFeatures() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO);
102     callTypeIcon.setShowHd(MotorolaUtils.shouldShowHdIconInCallLog(context, entry.getFeatures()));
103     callTypeIcon.setShowWifi(
104         MotorolaUtils.shouldShowWifiIconInCallLog(context, entry.getFeatures()));
105 
106     callTypeText.setText(callTypeHelper.getCallTypeText(callType, isVideoCall, isPulledCall));
107     callTime.setText(CallEntryFormatter.formatDate(context, entry.getDate()));
108     if (CallTypeHelper.isMissedCallType(callType)) {
109       callDuration.setVisibility(View.GONE);
110     } else {
111       callDuration.setVisibility(View.VISIBLE);
112       callDuration.setText(
113           CallEntryFormatter.formatDurationAndDataUsage(
114               context, entry.getDuration(), entry.getDataUsage()));
115       callDuration.setContentDescription(
116           CallEntryFormatter.formatDurationAndDataUsageA11y(
117               context, entry.getDuration(), entry.getDataUsage()));
118     }
119     setMultimediaDetails(number, entry, showMultimediaDivider);
120   }
121 
setMultimediaDetails(String number, CallDetailsEntry entry, boolean showDivider)122   private void setMultimediaDetails(String number, CallDetailsEntry entry, boolean showDivider) {
123     multimediaDivider.setVisibility(showDivider ? View.VISIBLE : View.GONE);
124     if (entry.getHistoryResultsList().isEmpty()) {
125       LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "no data, hiding UI");
126       multimediaDetailsContainer.setVisibility(View.GONE);
127     } else {
128 
129       HistoryResult historyResult = entry.getHistoryResults(0);
130       multimediaDetailsContainer.setVisibility(View.VISIBLE);
131       multimediaDetailsContainer.setOnClickListener((v) -> startSmsIntent(context, number));
132       multimediaImageContainer.setClipToOutline(true);
133 
134       if (!TextUtils.isEmpty(historyResult.getImageUri())) {
135         LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "setting image");
136         multimediaImageContainer.setVisibility(View.VISIBLE);
137         multimediaImage.setImageURI(Uri.parse(historyResult.getImageUri()));
138         multimediaDetails.setText(
139             isIncoming(historyResult) ? R.string.received_a_photo : R.string.sent_a_photo);
140       } else {
141         LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "no image");
142       }
143 
144       // Set text after image to overwrite the received/sent a photo text
145       if (!TextUtils.isEmpty(historyResult.getText())) {
146         LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "showing text");
147         multimediaDetails.setText(
148             context.getString(R.string.message_in_quotes, historyResult.getText()));
149       } else {
150         LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "no text");
151       }
152 
153       if (entry.getHistoryResultsList().size() > 1
154           && !TextUtils.isEmpty(entry.getHistoryResults(1).getText())) {
155         LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "showing post call note");
156         postCallNote.setVisibility(View.VISIBLE);
157         postCallNote.setText(
158             context.getString(R.string.message_in_quotes, entry.getHistoryResults(1).getText()));
159         postCallNote.setOnClickListener((v) -> startSmsIntent(context, number));
160       } else {
161         LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "no post call note");
162       }
163     }
164   }
165 
startSmsIntent(Context context, String number)166   private void startSmsIntent(Context context, String number) {
167     DialerUtils.startActivityWithErrorToast(context, IntentUtil.getSendSmsIntent(number));
168   }
169 
isIncoming(@onNull HistoryResult historyResult)170   private static boolean isIncoming(@NonNull HistoryResult historyResult) {
171     return historyResult.getType() == Type.INCOMING_POST_CALL
172         || historyResult.getType() == Type.INCOMING_CALL_COMPOSER;
173   }
174 
getColorForCallType(Context context, int callType)175   private static @ColorInt int getColorForCallType(Context context, int callType) {
176     switch (callType) {
177       case AppCompatConstants.CALLS_OUTGOING_TYPE:
178       case AppCompatConstants.CALLS_VOICEMAIL_TYPE:
179       case AppCompatConstants.CALLS_BLOCKED_TYPE:
180       case AppCompatConstants.CALLS_INCOMING_TYPE:
181       case AppCompatConstants.CALLS_ANSWERED_EXTERNALLY_TYPE:
182       case AppCompatConstants.CALLS_REJECTED_TYPE:
183         return ContextCompat.getColor(context, R.color.dialer_secondary_text_color);
184       case AppCompatConstants.CALLS_MISSED_TYPE:
185       default:
186         // It is possible for users to end up with calls with unknown call types in their
187         // call history, possibly due to 3rd party call log implementations (e.g. to
188         // distinguish between rejected and missed calls). Instead of crashing, just
189         // assume that all unknown call types are missed calls.
190         return ContextCompat.getColor(context, R.color.missed_call);
191     }
192   }
193 }
194