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
17package com.android.incallui.contactgrid;
18
19import android.content.Context;
20import android.graphics.drawable.Drawable;
21import android.support.annotation.Nullable;
22import android.telephony.PhoneNumberUtils;
23import android.text.BidiFormatter;
24import android.text.TextDirectionHeuristics;
25import android.text.TextUtils;
26import com.android.dialer.common.Assert;
27import com.android.incallui.call.DialerCall.State;
28import com.android.incallui.incall.protocol.PrimaryCallState;
29import com.android.incallui.incall.protocol.PrimaryInfo;
30import com.android.incallui.videotech.utils.SessionModificationState;
31import 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 */
44public 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
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
60  private TopRow() {}
61
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
108  private static CharSequence spanDisplayNumber(String displayNumber) {
109    return PhoneNumberUtils.createTtsSpannable(
110        BidiFormatter.getInstance().unicodeWrap(displayNumber, TextDirectionHeuristics.LTR));
111  }
112
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
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
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
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
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
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
203  private static boolean isAccount(PrimaryCallState state) {
204    return !TextUtils.isEmpty(state.connectionLabel) && TextUtils.isEmpty(state.gatewayNumber);
205  }
206}
207