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.support.annotation.Nullable; 21 import android.telephony.PhoneNumberUtils; 22 import android.text.BidiFormatter; 23 import android.text.TextDirectionHeuristics; 24 import android.text.TextUtils; 25 import com.android.contacts.common.compat.PhoneNumberUtilsCompat; 26 import com.android.incallui.call.DialerCall.State; 27 import com.android.incallui.incall.protocol.PrimaryCallState; 28 import com.android.incallui.incall.protocol.PrimaryInfo; 29 30 /** 31 * Gets the content of the bottom row. For example: 32 * 33 * <ul> 34 * <li>Mobile +1 (650) 253-0000 35 * <li>[HD attempting icon]/[HD icon] 00:15 36 * <li>Call ended 37 * <li>Hanging up 38 * </ul> 39 */ 40 public class BottomRow { 41 42 /** Content of the bottom row. */ 43 public static class Info { 44 45 @Nullable public final CharSequence label; 46 public final boolean isTimerVisible; 47 public final boolean isWorkIconVisible; 48 public final boolean isHdAttemptingIconVisible; 49 public final boolean isHdIconVisible; 50 public final boolean isForwardIconVisible; 51 public final boolean isSpamIconVisible; 52 public final boolean shouldPopulateAccessibilityEvent; 53 Info( @ullable CharSequence label, boolean isTimerVisible, boolean isWorkIconVisible, boolean isHdAttemptingIconVisible, boolean isHdIconVisible, boolean isForwardIconVisible, boolean isSpamIconVisible, boolean shouldPopulateAccessibilityEvent)54 public Info( 55 @Nullable CharSequence label, 56 boolean isTimerVisible, 57 boolean isWorkIconVisible, 58 boolean isHdAttemptingIconVisible, 59 boolean isHdIconVisible, 60 boolean isForwardIconVisible, 61 boolean isSpamIconVisible, 62 boolean shouldPopulateAccessibilityEvent) { 63 this.label = label; 64 this.isTimerVisible = isTimerVisible; 65 this.isWorkIconVisible = isWorkIconVisible; 66 this.isHdAttemptingIconVisible = isHdAttemptingIconVisible; 67 this.isHdIconVisible = isHdIconVisible; 68 this.isForwardIconVisible = isForwardIconVisible; 69 this.isSpamIconVisible = isSpamIconVisible; 70 this.shouldPopulateAccessibilityEvent = shouldPopulateAccessibilityEvent; 71 } 72 } 73 BottomRow()74 private BottomRow() {} 75 getInfo(Context context, PrimaryCallState state, PrimaryInfo primaryInfo)76 public static Info getInfo(Context context, PrimaryCallState state, PrimaryInfo primaryInfo) { 77 CharSequence label; 78 boolean isTimerVisible = state.state == State.ACTIVE; 79 boolean isForwardIconVisible = state.isForwardedNumber; 80 boolean isWorkIconVisible = state.isWorkCall; 81 boolean isHdIconVisible = state.isHdAudioCall && !isForwardIconVisible; 82 boolean isHdAttemptingIconVisible = state.isHdAttempting; 83 boolean isSpamIconVisible = false; 84 boolean shouldPopulateAccessibilityEvent = true; 85 86 if (isIncoming(state) && primaryInfo.isSpam) { 87 label = context.getString(R.string.contact_grid_incoming_suspected_spam); 88 isSpamIconVisible = true; 89 isHdIconVisible = false; 90 } else if (state.state == State.DISCONNECTING) { 91 // While in the DISCONNECTING state we display a "Hanging up" message in order to make the UI 92 // feel more responsive. (In GSM it's normal to see a delay of a couple of seconds while 93 // negotiating the disconnect with the network, so the "Hanging up" state at least lets the 94 // user know that we're doing something. This state is currently not used with CDMA.) 95 label = context.getString(R.string.incall_hanging_up); 96 } else if (state.state == State.DISCONNECTED) { 97 label = state.disconnectCause.getLabel(); 98 if (TextUtils.isEmpty(label)) { 99 label = context.getString(R.string.incall_call_ended); 100 } 101 } else if (!TextUtils.isEmpty(state.callbackNumber)) { 102 // This is used for carriers like Project Fi to show the callback number for emergency calls. 103 label = 104 context.getString( 105 R.string.contact_grid_callback_number, 106 PhoneNumberUtils.formatNumber(state.callbackNumber)); 107 isTimerVisible = false; 108 } else { 109 label = getLabelForPhoneNumber(primaryInfo); 110 shouldPopulateAccessibilityEvent = primaryInfo.nameIsNumber; 111 } 112 113 return new Info( 114 label, 115 isTimerVisible, 116 isWorkIconVisible, 117 isHdAttemptingIconVisible, 118 isHdIconVisible, 119 isForwardIconVisible, 120 isSpamIconVisible, 121 shouldPopulateAccessibilityEvent); 122 } 123 getLabelForPhoneNumber(PrimaryInfo primaryInfo)124 private static CharSequence getLabelForPhoneNumber(PrimaryInfo primaryInfo) { 125 if (primaryInfo.location != null) { 126 return primaryInfo.location; 127 } 128 if (!TextUtils.isEmpty(primaryInfo.number)) { 129 CharSequence spannedNumber = spanDisplayNumber(primaryInfo.number); 130 if (primaryInfo.label == null) { 131 return spannedNumber; 132 } else { 133 return TextUtils.concat(primaryInfo.label, " ", spannedNumber); 134 } 135 } 136 return null; 137 } 138 spanDisplayNumber(String displayNumber)139 private static CharSequence spanDisplayNumber(String displayNumber) { 140 return PhoneNumberUtilsCompat.createTtsSpannable( 141 BidiFormatter.getInstance().unicodeWrap(displayNumber, TextDirectionHeuristics.LTR)); 142 } 143 isIncoming(PrimaryCallState state)144 private static boolean isIncoming(PrimaryCallState state) { 145 return state.state == State.INCOMING || state.state == State.CALL_WAITING; 146 } 147 } 148