• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Info(@ullable CharSequence label, @Nullable Drawable icon, boolean labelIsSingleLine)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 
TopRow()61   private TopRow() {}
62 
getInfo(Context context, PrimaryCallState state, PrimaryInfo primaryInfo)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 
spanDisplayNumber(String displayNumber)112   private static CharSequence spanDisplayNumber(String displayNumber) {
113     return PhoneNumberUtils.createTtsSpannable(
114         BidiFormatter.getInstance().unicodeWrap(displayNumber, TextDirectionHeuristics.LTR));
115   }
116 
shouldShowNumber(PrimaryInfo primaryInfo, boolean isIncoming)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 
getLabelForIncoming(Context context, PrimaryCallState state)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 
getLabelForIncomingVideo( Context context, @SessionModificationState int sessionModificationState, boolean isWifi)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 
getLabelForDialing(Context context, PrimaryCallState state)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 
getConnectionLabel(PrimaryCallState state)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 
getLabelForVideoRequest(Context context, PrimaryCallState state)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 
isAccount(PrimaryCallState state)223   private static boolean isAccount(PrimaryCallState state) {
224     return !TextUtils.isEmpty(state.connectionLabel()) && TextUtils.isEmpty(state.gatewayNumber());
225   }
226 }
227