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.calllog.ui.menu; 18 19 import android.content.Context; 20 import android.provider.CallLog.Calls; 21 import android.telecom.PhoneAccountHandle; 22 import android.text.TextUtils; 23 import com.android.dialer.blockreportspam.BlockReportSpamDialogInfo; 24 import com.android.dialer.calldetails.CallDetailsActivity; 25 import com.android.dialer.callintent.CallInitiationType; 26 import com.android.dialer.calllog.model.CoalescedRow; 27 import com.android.dialer.calllogutils.CallLogContactTypes; 28 import com.android.dialer.calllogutils.PhoneNumberDisplayUtil; 29 import com.android.dialer.dialercontact.DialerContact; 30 import com.android.dialer.historyitemactions.DividerModule; 31 import com.android.dialer.historyitemactions.HistoryItemActionModule; 32 import com.android.dialer.historyitemactions.IntentModule; 33 import com.android.dialer.historyitemactions.SharedModules; 34 import com.android.dialer.logging.ReportingLocation; 35 import com.android.dialer.phonenumberutil.PhoneNumberHelper; 36 import com.android.dialer.telecom.TelecomUtil; 37 import com.google.common.base.Optional; 38 import java.util.ArrayList; 39 import java.util.Collections; 40 import java.util.List; 41 42 /** 43 * Configures the modules for the bottom sheet; these are the rows below the top row (primary 44 * action) in the bottom sheet. 45 */ 46 @SuppressWarnings("Guava") 47 final class Modules { 48 fromRow(Context context, CoalescedRow row)49 static List<HistoryItemActionModule> fromRow(Context context, CoalescedRow row) { 50 // Conditionally add each module, which are items in the bottom sheet's menu. 51 List<HistoryItemActionModule> modules = new ArrayList<>(); 52 53 String normalizedNumber = row.number().getNormalizedNumber(); 54 boolean canPlaceCalls = 55 PhoneNumberHelper.canPlaceCallsTo(normalizedNumber, row.numberPresentation()); 56 57 if (canPlaceCalls) { 58 modules.addAll(createModulesForCalls(context, row, normalizedNumber)); 59 Optional<HistoryItemActionModule> moduleForSendingTextMessage = 60 SharedModules.createModuleForSendingTextMessage( 61 context, normalizedNumber, row.numberAttributes().getIsBlocked()); 62 if (moduleForSendingTextMessage.isPresent()) { 63 modules.add(moduleForSendingTextMessage.get()); 64 } 65 } 66 67 if (!modules.isEmpty()) { 68 modules.add(new DividerModule()); 69 } 70 71 72 // TODO(zachh): Module for CallComposer. 73 74 if (canPlaceCalls) { 75 Optional<HistoryItemActionModule> moduleForAddingToContacts = 76 SharedModules.createModuleForAddingToContacts( 77 context, 78 row.number(), 79 row.numberAttributes().getName(), 80 row.numberAttributes().getLookupUri(), 81 row.numberAttributes().getIsBlocked(), 82 row.numberAttributes().getIsSpam()); 83 if (moduleForAddingToContacts.isPresent()) { 84 modules.add(moduleForAddingToContacts.get()); 85 } 86 87 BlockReportSpamDialogInfo blockReportSpamDialogInfo = 88 BlockReportSpamDialogInfo.newBuilder() 89 .setNormalizedNumber(row.number().getNormalizedNumber()) 90 .setCountryIso(row.number().getCountryIso()) 91 .setCallType(row.callType()) 92 .setReportingLocation(ReportingLocation.Type.CALL_LOG_HISTORY) 93 .setContactSource(row.numberAttributes().getContactSource()) 94 .build(); 95 modules.addAll( 96 SharedModules.createModulesHandlingBlockedOrSpamNumber( 97 context, 98 blockReportSpamDialogInfo, 99 row.numberAttributes().getIsBlocked(), 100 row.numberAttributes().getIsSpam())); 101 102 Optional<HistoryItemActionModule> moduleForCopyingNumber = 103 SharedModules.createModuleForCopyingNumber(context, normalizedNumber); 104 if (moduleForCopyingNumber.isPresent()) { 105 modules.add(moduleForCopyingNumber.get()); 106 } 107 } 108 109 // TODO(zachh): Revisit if DialerContact is the best thing to pass to CallDetails; could 110 // it use a HistoryItemPrimaryActionInfo instead? 111 modules.add(createModuleForAccessingCallDetails(context, row)); 112 113 modules.add(new DeleteCallLogItemModule(context, row.coalescedIds())); 114 115 return modules; 116 } 117 createModulesForCalls( Context context, CoalescedRow row, String normalizedNumber)118 private static List<HistoryItemActionModule> createModulesForCalls( 119 Context context, CoalescedRow row, String normalizedNumber) { 120 // Don't add call options if a number is blocked. 121 if (row.numberAttributes().getIsBlocked()) { 122 return Collections.emptyList(); 123 } 124 125 List<HistoryItemActionModule> modules = new ArrayList<>(); 126 PhoneAccountHandle phoneAccountHandle = 127 TelecomUtil.composePhoneAccountHandle( 128 row.phoneAccountComponentName(), row.phoneAccountId()); 129 130 // Add an audio call item 131 modules.add( 132 IntentModule.newCallModule( 133 context, normalizedNumber, phoneAccountHandle, CallInitiationType.Type.CALL_LOG)); 134 135 // Add a video item if (1) the call log entry is for a video call, and (2) the call is not spam. 136 if ((row.features() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO 137 && !row.numberAttributes().getIsSpam()) { 138 modules.add( 139 IntentModule.newVideoCallModule( 140 context, normalizedNumber, phoneAccountHandle, CallInitiationType.Type.CALL_LOG)); 141 } 142 143 // TODO(zachh): Also show video option if the call log entry is for an audio call but video 144 // capabilities are present? 145 146 return modules; 147 } 148 createModuleForAccessingCallDetails( Context context, CoalescedRow row)149 private static HistoryItemActionModule createModuleForAccessingCallDetails( 150 Context context, CoalescedRow row) { 151 boolean canReportAsInvalidNumber = row.numberAttributes().getCanReportAsInvalidNumber(); 152 boolean canSupportAssistedDialing = !TextUtils.isEmpty(row.numberAttributes().getLookupUri()); 153 154 return new IntentModule( 155 context, 156 CallDetailsActivity.newInstance( 157 context, 158 row.coalescedIds(), 159 createDialerContactFromRow(context, row), 160 canReportAsInvalidNumber, 161 canSupportAssistedDialing), 162 R.string.call_details_menu_label, 163 R.drawable.quantum_ic_info_outline_vd_theme_24); 164 } 165 createDialerContactFromRow(Context context, CoalescedRow row)166 private static DialerContact createDialerContactFromRow(Context context, CoalescedRow row) { 167 Optional<String> presentationName = 168 PhoneNumberDisplayUtil.getNameForPresentation(context, row.numberPresentation()); 169 if (presentationName.isPresent()) { 170 return DialerContact.newBuilder() 171 .setNameOrNumber(presentationName.get()) 172 .setContactType(CallLogContactTypes.getContactType(row)) 173 .build(); 174 } 175 176 String normalizedNumber = row.number().getNormalizedNumber(); 177 DialerContact.Builder dialerContactBuilder = 178 DialerContact.newBuilder() 179 .setNumber(normalizedNumber) 180 .setContactType(CallLogContactTypes.getContactType(row)) 181 .setPhotoId(row.numberAttributes().getPhotoId()); 182 183 if (!row.numberAttributes().getName().isEmpty()) { 184 dialerContactBuilder.setNameOrNumber(row.numberAttributes().getName()); 185 if (row.formattedNumber() != null) { 186 dialerContactBuilder.setDisplayNumber(row.formattedNumber()); 187 } 188 } else if (!TextUtils.isEmpty(row.formattedNumber())) { 189 dialerContactBuilder.setNameOrNumber(row.formattedNumber()); 190 } 191 192 dialerContactBuilder.setNumberLabel(row.numberAttributes().getNumberTypeLabel()); 193 dialerContactBuilder.setPhotoUri(row.numberAttributes().getPhotoUri()); 194 dialerContactBuilder.setContactUri(row.numberAttributes().getLookupUri()); 195 196 return dialerContactBuilder.build(); 197 } 198 } 199