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.v4.os.BuildCompat; 26 import android.support.v7.widget.RecyclerView.ViewHolder; 27 import android.text.TextUtils; 28 import android.view.View; 29 import android.widget.ImageView; 30 import android.widget.TextView; 31 import com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry; 32 import com.android.dialer.calllogutils.CallLogDates; 33 import com.android.dialer.calllogutils.CallLogDurations; 34 import com.android.dialer.calllogutils.CallTypeHelper; 35 import com.android.dialer.calllogutils.CallTypeIconsView; 36 import com.android.dialer.common.LogUtil; 37 import com.android.dialer.enrichedcall.historyquery.proto.HistoryResult; 38 import com.android.dialer.enrichedcall.historyquery.proto.HistoryResult.Type; 39 import com.android.dialer.glidephotomanager.PhotoInfo; 40 import com.android.dialer.oem.MotorolaUtils; 41 import com.android.dialer.util.DialerUtils; 42 import com.android.dialer.util.IntentUtil; 43 44 /** ViewHolder for call entries in {@link OldCallDetailsActivity} or {@link CallDetailsActivity}. */ 45 public class CallDetailsEntryViewHolder extends ViewHolder { 46 47 /** Listener for the call details header */ 48 interface CallDetailsEntryListener { 49 /** Shows RTT transcript. */ showRttTranscript(String transcriptId, String primaryText, PhotoInfo photoInfo)50 void showRttTranscript(String transcriptId, String primaryText, PhotoInfo photoInfo); 51 } 52 53 private final CallDetailsEntryListener callDetailsEntryListener; 54 55 private final CallTypeIconsView callTypeIcon; 56 private final TextView callTypeText; 57 private final TextView callTime; 58 private final TextView callDuration; 59 60 private final View multimediaImageContainer; 61 private final View multimediaDetailsContainer; 62 private final View multimediaDivider; 63 64 private final TextView multimediaDetails; 65 private final TextView postCallNote; 66 private final TextView rttTranscript; 67 68 private final ImageView multimediaImage; 69 70 // TODO(maxwelb): Display this when location is stored - a bug 71 @SuppressWarnings("unused") 72 private final TextView multimediaAttachmentsNumber; 73 74 private final Context context; 75 CallDetailsEntryViewHolder( View container, CallDetailsEntryListener callDetailsEntryListener)76 public CallDetailsEntryViewHolder( 77 View container, CallDetailsEntryListener callDetailsEntryListener) { 78 super(container); 79 context = container.getContext(); 80 81 callTypeIcon = (CallTypeIconsView) container.findViewById(R.id.call_direction); 82 callTypeText = (TextView) container.findViewById(R.id.call_type); 83 callTime = (TextView) container.findViewById(R.id.call_time); 84 callDuration = (TextView) container.findViewById(R.id.call_duration); 85 86 multimediaImageContainer = container.findViewById(R.id.multimedia_image_container); 87 multimediaDetailsContainer = container.findViewById(R.id.ec_container); 88 multimediaDivider = container.findViewById(R.id.divider); 89 multimediaDetails = (TextView) container.findViewById(R.id.multimedia_details); 90 postCallNote = (TextView) container.findViewById(R.id.post_call_note); 91 multimediaImage = (ImageView) container.findViewById(R.id.multimedia_image); 92 multimediaAttachmentsNumber = 93 (TextView) container.findViewById(R.id.multimedia_attachments_number); 94 rttTranscript = container.findViewById(R.id.rtt_transcript); 95 this.callDetailsEntryListener = callDetailsEntryListener; 96 } 97 setCallDetails( String number, String primaryText, PhotoInfo photoInfo, CallDetailsEntry entry, CallTypeHelper callTypeHelper, boolean showMultimediaDivider)98 void setCallDetails( 99 String number, 100 String primaryText, 101 PhotoInfo photoInfo, 102 CallDetailsEntry entry, 103 CallTypeHelper callTypeHelper, 104 boolean showMultimediaDivider) { 105 int callType = entry.getCallType(); 106 boolean isVideoCall = (entry.getFeatures() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO; 107 boolean isPulledCall = 108 (entry.getFeatures() & Calls.FEATURES_PULLED_EXTERNALLY) 109 == Calls.FEATURES_PULLED_EXTERNALLY; 110 boolean isDuoCall = entry.getIsDuoCall(); 111 boolean isRttCall = 112 BuildCompat.isAtLeastP() 113 && (entry.getFeatures() & Calls.FEATURES_RTT) == Calls.FEATURES_RTT; 114 115 callTime.setTextColor(getColorForCallType(context, callType)); 116 callTypeIcon.clear(); 117 callTypeIcon.add(callType); 118 callTypeIcon.setShowVideo(isVideoCall); 119 callTypeIcon.setShowHd( 120 (entry.getFeatures() & Calls.FEATURES_HD_CALL) == Calls.FEATURES_HD_CALL); 121 callTypeIcon.setShowWifi( 122 MotorolaUtils.shouldShowWifiIconInCallLog(context, entry.getFeatures())); 123 if (BuildCompat.isAtLeastP()) { 124 callTypeIcon.setShowRtt((entry.getFeatures() & Calls.FEATURES_RTT) == Calls.FEATURES_RTT); 125 } 126 127 callTypeText.setText( 128 callTypeHelper.getCallTypeText(callType, isVideoCall, isPulledCall, isDuoCall)); 129 callTime.setText(CallLogDates.formatDate(context, entry.getDate())); 130 131 if (CallTypeHelper.isMissedCallType(callType)) { 132 callDuration.setVisibility(View.GONE); 133 } else { 134 callDuration.setVisibility(View.VISIBLE); 135 callDuration.setText( 136 CallLogDurations.formatDurationAndDataUsage( 137 context, entry.getDuration(), entry.getDataUsage())); 138 callDuration.setContentDescription( 139 CallLogDurations.formatDurationAndDataUsageA11y( 140 context, entry.getDuration(), entry.getDataUsage())); 141 } 142 setMultimediaDetails(number, entry, showMultimediaDivider); 143 if (isRttCall) { 144 if (entry.getHasRttTranscript()) { 145 rttTranscript.setText(R.string.rtt_transcript_link); 146 rttTranscript.setTextAppearance(R.style.RttTranscriptLink); 147 rttTranscript.setClickable(true); 148 rttTranscript.setOnClickListener( 149 v -> 150 callDetailsEntryListener.showRttTranscript( 151 entry.getCallMappingId(), primaryText, photoInfo)); 152 } else { 153 rttTranscript.setText(R.string.rtt_transcript_not_available); 154 rttTranscript.setTextAppearance(R.style.RttTranscriptMessage); 155 rttTranscript.setClickable(false); 156 } 157 rttTranscript.setVisibility(View.VISIBLE); 158 } else { 159 rttTranscript.setVisibility(View.GONE); 160 } 161 } 162 setMultimediaDetails(String number, CallDetailsEntry entry, boolean showDivider)163 private void setMultimediaDetails(String number, CallDetailsEntry entry, boolean showDivider) { 164 multimediaDivider.setVisibility(showDivider ? View.VISIBLE : View.GONE); 165 if (entry.getHistoryResultsList().isEmpty()) { 166 LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "no data, hiding UI"); 167 multimediaDetailsContainer.setVisibility(View.GONE); 168 } else { 169 170 HistoryResult historyResult = entry.getHistoryResults(0); 171 multimediaDetailsContainer.setVisibility(View.VISIBLE); 172 multimediaDetailsContainer.setOnClickListener((v) -> startSmsIntent(context, number)); 173 multimediaImageContainer.setOnClickListener((v) -> startSmsIntent(context, number)); 174 multimediaImageContainer.setClipToOutline(true); 175 176 if (!TextUtils.isEmpty(historyResult.getImageUri())) { 177 LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "setting image"); 178 multimediaImageContainer.setVisibility(View.VISIBLE); 179 multimediaImage.setImageURI(Uri.parse(historyResult.getImageUri())); 180 multimediaDetails.setText( 181 isIncoming(historyResult) ? R.string.received_a_photo : R.string.sent_a_photo); 182 } else { 183 LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "no image"); 184 } 185 186 // Set text after image to overwrite the received/sent a photo text 187 if (!TextUtils.isEmpty(historyResult.getText())) { 188 LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "showing text"); 189 multimediaDetails.setText( 190 context.getString(R.string.message_in_quotes, historyResult.getText())); 191 } else { 192 LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "no text"); 193 } 194 195 if (entry.getHistoryResultsList().size() > 1 196 && !TextUtils.isEmpty(entry.getHistoryResults(1).getText())) { 197 LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "showing post call note"); 198 postCallNote.setVisibility(View.VISIBLE); 199 postCallNote.setText( 200 context.getString(R.string.message_in_quotes, entry.getHistoryResults(1).getText())); 201 postCallNote.setOnClickListener((v) -> startSmsIntent(context, number)); 202 } else { 203 LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "no post call note"); 204 } 205 } 206 } 207 startSmsIntent(Context context, String number)208 private void startSmsIntent(Context context, String number) { 209 DialerUtils.startActivityWithErrorToast(context, IntentUtil.getSendSmsIntent(number)); 210 } 211 isIncoming(@onNull HistoryResult historyResult)212 private static boolean isIncoming(@NonNull HistoryResult historyResult) { 213 return historyResult.getType() == Type.INCOMING_POST_CALL 214 || historyResult.getType() == Type.INCOMING_CALL_COMPOSER; 215 } 216 getColorForCallType(Context context, int callType)217 private static @ColorInt int getColorForCallType(Context context, int callType) { 218 switch (callType) { 219 case Calls.OUTGOING_TYPE: 220 case Calls.VOICEMAIL_TYPE: 221 case Calls.BLOCKED_TYPE: 222 case Calls.INCOMING_TYPE: 223 case Calls.ANSWERED_EXTERNALLY_TYPE: 224 case Calls.REJECTED_TYPE: 225 return ContextCompat.getColor(context, R.color.dialer_secondary_text_color); 226 case Calls.MISSED_TYPE: 227 default: 228 // It is possible for users to end up with calls with unknown call types in their 229 // call history, possibly due to 3rd party call log implementations (e.g. to 230 // distinguish between rejected and missed calls). Instead of crashing, just 231 // assume that all unknown call types are missed calls. 232 return ContextCompat.getColor(context, R.color.dialer_red); 233 } 234 } 235 } 236