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