Home | History | Annotate | Download | only in contactgrid
      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