1 /* 2 * Copyright (C) 2016 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.incallui.contactgrid; 18 19 import android.content.Context; 20 import android.graphics.drawable.Drawable; 21 import android.support.annotation.Nullable; 22 import android.telephony.PhoneNumberUtils; 23 import android.text.BidiFormatter; 24 import android.text.TextDirectionHeuristics; 25 import android.text.TextUtils; 26 import com.android.dialer.common.Assert; 27 import com.android.dialer.common.LogUtil; 28 import com.android.incallui.call.DialerCall.State; 29 import com.android.incallui.incall.protocol.PrimaryCallState; 30 import com.android.incallui.incall.protocol.PrimaryInfo; 31 import com.android.incallui.videotech.utils.SessionModificationState; 32 import com.android.incallui.videotech.utils.VideoUtils; 33 34 /** 35 * Gets the content of the top row. For example: 36 * 37 * <ul> 38 * <li>Captain Holt ON HOLD 39 * <li>Calling... 40 * <li>[Wi-Fi icon] Calling via Starbucks Wi-Fi 41 * <li>[Wi-Fi icon] Starbucks Wi-Fi 42 * <li>Call from 43 * </ul> 44 */ 45 public class TopRow { 46 47 /** Content of the top row. */ 48 public static class Info { 49 50 @Nullable public final CharSequence label; 51 @Nullable public final Drawable icon; 52 public final boolean labelIsSingleLine; 53 54 public Info(@Nullable CharSequence label, @Nullable Drawable icon, boolean labelIsSingleLine) { 55 this.label = label; 56 this.icon = icon; 57 this.labelIsSingleLine = labelIsSingleLine; 58 } 59 } 60 61 private TopRow() {} 62 63 public static Info getInfo(Context context, PrimaryCallState state, PrimaryInfo primaryInfo) { 64 CharSequence label = null; 65 Drawable icon = state.connectionIcon(); 66 boolean labelIsSingleLine = true; 67 68 if (state.isWifi() && icon == null) { 69 icon = context.getDrawable(R.drawable.quantum_ic_network_wifi_vd_theme_24); 70 } 71 72 if (state.state() == State.INCOMING || state.state() == State.CALL_WAITING) { 73 // Call from 74 // [Wi-Fi icon] Video call from 75 // Hey Jake, pick up! 76 if (!TextUtils.isEmpty(state.callSubject())) { 77 label = state.callSubject(); 78 labelIsSingleLine = false; 79 } else { 80 label = getLabelForIncoming(context, state); 81 // Show phone number if it's not displayed in name (center row) or location field (bottom 82 // row). 83 if (shouldShowNumber(primaryInfo, true /* isIncoming */)) { 84 label = TextUtils.concat(label, " ", spanDisplayNumber(primaryInfo.number())); 85 } 86 } 87 } else if (VideoUtils.hasSentVideoUpgradeRequest(state.sessionModificationState()) 88 || VideoUtils.hasReceivedVideoUpgradeRequest(state.sessionModificationState())) { 89 label = getLabelForVideoRequest(context, state); 90 } else if (state.state() == State.PULLING) { 91 label = context.getString(R.string.incall_transferring); 92 } else if (state.state() == State.DIALING || state.state() == State.CONNECTING) { 93 // [Wi-Fi icon] Calling via Google Guest 94 // Calling... 95 label = getLabelForDialing(context, state); 96 } else if (state.state() == State.ACTIVE && state.isRemotelyHeld()) { 97 label = context.getString(R.string.incall_remotely_held); 98 } else if (state.state() == State.ACTIVE 99 && shouldShowNumber(primaryInfo, false /* isIncoming */)) { 100 label = spanDisplayNumber(primaryInfo.number()); 101 } else if (state.state() == State.CALL_PENDING && !TextUtils.isEmpty(state.customLabel())) { 102 label = state.customLabel(); 103 } else { 104 // Video calling... 105 // [Wi-Fi icon] Starbucks Wi-Fi 106 label = getConnectionLabel(state); 107 } 108 109 return new Info(label, icon, labelIsSingleLine); 110 } 111 112 private static CharSequence spanDisplayNumber(String displayNumber) { 113 return PhoneNumberUtils.createTtsSpannable( 114 BidiFormatter.getInstance().unicodeWrap(displayNumber, TextDirectionHeuristics.LTR)); 115 } 116 117 private static boolean shouldShowNumber(PrimaryInfo primaryInfo, boolean isIncoming) { 118 if (primaryInfo.nameIsNumber()) { 119 return false; 120 } 121 // Don't show number since it's already shown in bottom row of incoming screen if there is no 122 // location info. 123 if (primaryInfo.location() == null && isIncoming) { 124 return false; 125 } 126 if (primaryInfo.isLocalContact() && !isIncoming) { 127 return false; 128 } 129 if (TextUtils.isEmpty(primaryInfo.number())) { 130 return false; 131 } 132 return true; 133 } 134 135 private static CharSequence getLabelForIncoming(Context context, PrimaryCallState state) { 136 if (state.isVideoCall()) { 137 return getLabelForIncomingVideo(context, state.sessionModificationState(), state.isWifi()); 138 } else if (state.isWifi() && !TextUtils.isEmpty(state.connectionLabel())) { 139 return state.connectionLabel(); 140 } else if (isAccount(state)) { 141 return context.getString( 142 R.string.contact_grid_incoming_via_template, state.connectionLabel()); 143 } else if (state.isWorkCall()) { 144 return context.getString(R.string.contact_grid_incoming_work_call); 145 } else { 146 return context.getString(R.string.contact_grid_incoming_voice_call); 147 } 148 } 149 150 private static CharSequence getLabelForIncomingVideo( 151 Context context, @SessionModificationState int sessionModificationState, boolean isWifi) { 152 if (sessionModificationState == SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) { 153 if (isWifi) { 154 return context.getString(R.string.contact_grid_incoming_wifi_video_call); 155 } else { 156 return context.getString(R.string.contact_grid_incoming_video_call); 157 } 158 } else { 159 if (isWifi) { 160 return context.getString(R.string.contact_grid_incoming_wifi_video_call); 161 } else { 162 return context.getString(R.string.contact_grid_incoming_video_call); 163 } 164 } 165 } 166 167 private static CharSequence getLabelForDialing(Context context, PrimaryCallState state) { 168 if (!TextUtils.isEmpty(state.connectionLabel()) && !state.isWifi()) { 169 return context.getString(R.string.incall_calling_via_template, state.connectionLabel()); 170 } else { 171 if (state.isVideoCall()) { 172 if (state.isWifi()) { 173 return context.getString(R.string.incall_wifi_video_call_requesting); 174 } else { 175 return context.getString(R.string.incall_video_call_requesting); 176 } 177 } 178 179 if (state.isAssistedDialed() && state.assistedDialingExtras() != null) { 180 LogUtil.i("TopRow.getLabelForDialing", "using assisted dialing label."); 181 String countryCode = 182 String.valueOf(state.assistedDialingExtras().transformedNumberCountryCallingCode()); 183 return context.getString( 184 R.string.incall_connecting_assited_dialed, 185 countryCode, 186 state.assistedDialingExtras().userHomeCountryCode()); 187 } 188 return context.getString(R.string.incall_connecting); 189 } 190 } 191 192 private static CharSequence getConnectionLabel(PrimaryCallState state) { 193 if (!TextUtils.isEmpty(state.connectionLabel()) 194 && (isAccount(state) || state.isWifi() || state.isConference())) { 195 // We normally don't show a "call state label" at all when active 196 // (but we can use the call state label to display the provider name). 197 return state.connectionLabel(); 198 } else { 199 return null; 200 } 201 } 202 203 private static CharSequence getLabelForVideoRequest(Context context, PrimaryCallState state) { 204 switch (state.sessionModificationState()) { 205 case SessionModificationState.WAITING_FOR_UPGRADE_TO_VIDEO_RESPONSE: 206 return context.getString(R.string.incall_video_call_upgrade_request); 207 case SessionModificationState.REQUEST_FAILED: 208 case SessionModificationState.UPGRADE_TO_VIDEO_REQUEST_FAILED: 209 return context.getString(R.string.incall_video_call_request_failed); 210 case SessionModificationState.REQUEST_REJECTED: 211 return context.getString(R.string.incall_video_call_request_rejected); 212 case SessionModificationState.UPGRADE_TO_VIDEO_REQUEST_TIMED_OUT: 213 return context.getString(R.string.incall_video_call_request_timed_out); 214 case SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST: 215 return getLabelForIncomingVideo(context, state.sessionModificationState(), state.isWifi()); 216 case SessionModificationState.NO_REQUEST: 217 default: 218 Assert.fail(); 219 return null; 220 } 221 } 222 223 private static boolean isAccount(PrimaryCallState state) { 224 return !TextUtils.isEmpty(state.connectionLabel()) && TextUtils.isEmpty(state.gatewayNumber()); 225 } 226 } 227