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.support.v7.widget.RecyclerView; 22 import android.telecom.PhoneAccount; 23 import android.text.TextUtils; 24 import android.view.View; 25 import android.view.View.OnClickListener; 26 import android.widget.ImageView; 27 import android.widget.QuickContactBadge; 28 import android.widget.RelativeLayout; 29 import android.widget.TextView; 30 import com.android.dialer.calldetails.CallDetailsActivityCommon.AssistedDialingNumberParseWorker; 31 import com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry; 32 import com.android.dialer.calllogutils.CallbackActionHelper.CallbackAction; 33 import com.android.dialer.common.Assert; 34 import com.android.dialer.common.LogUtil; 35 import com.android.dialer.common.concurrent.DialerExecutor.FailureListener; 36 import com.android.dialer.common.concurrent.DialerExecutor.SuccessListener; 37 import com.android.dialer.compat.telephony.TelephonyManagerCompat; 38 import com.android.dialer.contactphoto.ContactPhotoManager; 39 import com.android.dialer.dialercontact.DialerContact; 40 import com.android.dialer.glidephotomanager.GlidePhotoManagerComponent; 41 import com.android.dialer.logging.InteractionEvent; 42 import com.android.dialer.logging.Logger; 43 import com.android.dialer.phonenumberutil.PhoneNumberHelper; 44 import com.android.dialer.widget.BidiTextView; 45 46 /** 47 * ViewHolder for the header in {@link OldCallDetailsActivity} or {@link CallDetailsActivity}. 48 * 49 * <p>The header contains contact info and the primary callback button. 50 */ 51 public class CallDetailsHeaderViewHolder extends RecyclerView.ViewHolder 52 implements OnClickListener, FailureListener { 53 54 private final CallDetailsHeaderListener callDetailsHeaderListener; 55 private final ImageView callbackButton; 56 private final BidiTextView nameView; 57 private final BidiTextView numberView; 58 private final TextView networkView; 59 private final QuickContactBadge contactPhoto; 60 private final Context context; 61 private final TextView assistedDialingInternationalDirectDialCodeAndCountryCodeText; 62 private final RelativeLayout assistedDialingContainer; 63 64 private final String number; 65 private final String postDialDigits; 66 67 private @CallbackAction int callbackAction; 68 CallDetailsHeaderViewHolder( View container, String number, String postDialDigits, CallDetailsHeaderListener callDetailsHeaderListener)69 CallDetailsHeaderViewHolder( 70 View container, 71 String number, 72 String postDialDigits, 73 CallDetailsHeaderListener callDetailsHeaderListener) { 74 super(container); 75 context = container.getContext(); 76 callbackButton = container.findViewById(R.id.call_back_button); 77 nameView = container.findViewById(R.id.contact_name); 78 numberView = container.findViewById(R.id.phone_number); 79 networkView = container.findViewById(R.id.network); 80 contactPhoto = container.findViewById(R.id.quick_contact_photo); 81 assistedDialingInternationalDirectDialCodeAndCountryCodeText = 82 container.findViewById(R.id.assisted_dialing_text); 83 assistedDialingContainer = container.findViewById(R.id.assisted_dialing_container); 84 85 assistedDialingContainer.setOnClickListener( 86 callDetailsHeaderListener::openAssistedDialingSettings); 87 88 callbackButton.setOnClickListener(this); 89 90 this.number = number; 91 this.postDialDigits = postDialDigits; 92 this.callDetailsHeaderListener = callDetailsHeaderListener; 93 94 Logger.get(context) 95 .logQuickContactOnTouch( 96 contactPhoto, InteractionEvent.Type.OPEN_QUICK_CONTACT_FROM_CALL_DETAILS, true); 97 } 98 hasAssistedDialingFeature(Integer features)99 private boolean hasAssistedDialingFeature(Integer features) { 100 return (features & TelephonyManagerCompat.FEATURES_ASSISTED_DIALING) 101 == TelephonyManagerCompat.FEATURES_ASSISTED_DIALING; 102 } 103 updateAssistedDialingInfo(CallDetailsEntry callDetailsEntry)104 void updateAssistedDialingInfo(CallDetailsEntry callDetailsEntry) { 105 106 if (callDetailsEntry != null && hasAssistedDialingFeature(callDetailsEntry.getFeatures())) { 107 showAssistedDialingContainer(true); 108 callDetailsHeaderListener.createAssistedDialerNumberParserTask( 109 new CallDetailsActivityCommon.AssistedDialingNumberParseWorker(), 110 this::updateAssistedDialingText, 111 this::onFailure); 112 113 } else { 114 showAssistedDialingContainer(false); 115 } 116 } 117 showAssistedDialingContainer(boolean shouldShowContainer)118 private void showAssistedDialingContainer(boolean shouldShowContainer) { 119 if (shouldShowContainer) { 120 assistedDialingContainer.setVisibility(View.VISIBLE); 121 } else { 122 LogUtil.i( 123 "CallDetailsHeaderViewHolder.updateAssistedDialingInfo", 124 "hiding assisted dialing ui elements"); 125 assistedDialingContainer.setVisibility(View.GONE); 126 } 127 } 128 updateAssistedDialingText(Integer countryCode)129 private void updateAssistedDialingText(Integer countryCode) { 130 131 // Try and handle any poorly formed inputs. 132 if (countryCode <= 0) { 133 onFailure(new IllegalStateException()); 134 return; 135 } 136 137 LogUtil.i( 138 "CallDetailsHeaderViewHolder.updateAssistedDialingText", "Updating Assisted Dialing Text"); 139 assistedDialingInternationalDirectDialCodeAndCountryCodeText.setText( 140 context.getString( 141 R.string.assisted_dialing_country_code_entry, String.valueOf(countryCode))); 142 } 143 144 @Override onFailure(Throwable unused)145 public void onFailure(Throwable unused) { 146 assistedDialingInternationalDirectDialCodeAndCountryCodeText.setText( 147 R.string.assisted_dialing_country_code_entry_failure); 148 } 149 150 /** Populates the contact info fields based on the current contact information. */ updateContactInfo(DialerContact contact, @CallbackAction int callbackAction)151 void updateContactInfo(DialerContact contact, @CallbackAction int callbackAction) { 152 ContactPhotoManager.getInstance(context) 153 .loadDialerThumbnailOrPhoto( 154 contactPhoto, 155 contact.getContactUri().isEmpty() ? null : Uri.parse(contact.getContactUri()), 156 contact.getPhotoId(), 157 contact.getPhotoUri().isEmpty() ? null : Uri.parse(contact.getPhotoUri()), 158 contact.getNameOrNumber(), 159 contact.getContactType()); 160 161 // Hide the secondary text of the header by default. 162 // We will show it if needed (see below). 163 numberView.setVisibility(View.GONE); 164 numberView.setText(null); 165 166 if (PhoneNumberHelper.isLocalEmergencyNumber(context, contact.getNumber())) { 167 nameView.setText(context.getResources().getString(R.string.emergency_number)); 168 } else { 169 nameView.setText(contact.getNameOrNumber()); 170 if (!TextUtils.isEmpty(contact.getDisplayNumber())) { 171 numberView.setVisibility(View.VISIBLE); 172 String secondaryInfo = 173 TextUtils.isEmpty(contact.getNumberLabel()) 174 ? contact.getDisplayNumber() 175 : context.getString( 176 com.android.dialer.contacts.resources.R.string.call_subject_type_and_number, 177 contact.getNumberLabel(), 178 contact.getDisplayNumber()); 179 numberView.setText(secondaryInfo); 180 } 181 } 182 183 if (!TextUtils.isEmpty(contact.getSimDetails().getNetwork())) { 184 networkView.setVisibility(View.VISIBLE); 185 networkView.setText(contact.getSimDetails().getNetwork()); 186 if (contact.getSimDetails().getColor() != PhoneAccount.NO_HIGHLIGHT_COLOR) { 187 networkView.setTextColor(contact.getSimDetails().getColor()); 188 } 189 } 190 191 setCallbackAction(callbackAction); 192 } 193 updateContactInfo(CallDetailsHeaderInfo headerInfo, @CallbackAction int callbackAction)194 void updateContactInfo(CallDetailsHeaderInfo headerInfo, @CallbackAction int callbackAction) { 195 GlidePhotoManagerComponent.get(context) 196 .glidePhotoManager() 197 .loadQuickContactBadge(contactPhoto, headerInfo.getPhotoInfo()); 198 199 nameView.setText(headerInfo.getPrimaryText()); 200 if (!headerInfo.getSecondaryText().isEmpty()) { 201 numberView.setVisibility(View.VISIBLE); 202 numberView.setText(headerInfo.getSecondaryText()); 203 } else { 204 numberView.setVisibility(View.GONE); 205 numberView.setText(null); 206 } 207 208 setCallbackAction(callbackAction); 209 } 210 setCallbackAction(@allbackAction int callbackAction)211 private void setCallbackAction(@CallbackAction int callbackAction) { 212 this.callbackAction = callbackAction; 213 switch (callbackAction) { 214 case CallbackAction.DUO: 215 case CallbackAction.IMS_VIDEO: 216 callbackButton.setVisibility(View.VISIBLE); 217 callbackButton.setImageResource(R.drawable.quantum_ic_videocam_vd_theme_24); 218 break; 219 case CallbackAction.VOICE: 220 callbackButton.setVisibility(View.VISIBLE); 221 callbackButton.setImageResource(R.drawable.quantum_ic_call_vd_theme_24); 222 break; 223 case CallbackAction.NONE: 224 callbackButton.setVisibility(View.GONE); 225 break; 226 default: 227 throw Assert.createIllegalStateFailException("Invalid action: " + callbackAction); 228 } 229 } 230 231 @Override onClick(View view)232 public void onClick(View view) { 233 if (view == callbackButton) { 234 switch (callbackAction) { 235 case CallbackAction.IMS_VIDEO: 236 callDetailsHeaderListener.placeImsVideoCall(number); 237 break; 238 case CallbackAction.DUO: 239 callDetailsHeaderListener.placeDuoVideoCall(number); 240 break; 241 case CallbackAction.VOICE: 242 callDetailsHeaderListener.placeVoiceCall(number, postDialDigits); 243 break; 244 case CallbackAction.NONE: 245 default: 246 throw Assert.createIllegalStateFailException("Invalid action: " + callbackAction); 247 } 248 } else { 249 throw Assert.createIllegalStateFailException("View OnClickListener not implemented: " + view); 250 } 251 } 252 253 /** Listener for the call details header */ 254 interface CallDetailsHeaderListener { 255 256 /** Places an IMS video call. */ placeImsVideoCall(String phoneNumber)257 void placeImsVideoCall(String phoneNumber); 258 259 /** Places a Duo video call. */ placeDuoVideoCall(String phoneNumber)260 void placeDuoVideoCall(String phoneNumber); 261 262 /** Place a traditional voice call. */ placeVoiceCall(String phoneNumber, String postDialDigits)263 void placeVoiceCall(String phoneNumber, String postDialDigits); 264 265 /** Access the Assisted Dialing settings * */ openAssistedDialingSettings(View view)266 void openAssistedDialingSettings(View view); 267 createAssistedDialerNumberParserTask( AssistedDialingNumberParseWorker worker, SuccessListener<Integer> onSuccess, FailureListener onFailure)268 void createAssistedDialerNumberParserTask( 269 AssistedDialingNumberParseWorker worker, 270 SuccessListener<Integer> onSuccess, 271 FailureListener onFailure); 272 } 273 } 274