Home | History | Annotate | Download | only in telecom
      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.server.telecom;
     18 
     19 import android.net.Uri;
     20 import android.telecom.Connection;
     21 import android.telecom.ParcelableCall;
     22 import android.telecom.TelecomManager;
     23 
     24 import java.util.ArrayList;
     25 import java.util.List;
     26 
     27 /**
     28  * Utilities dealing with {@link ParcelableCall}.
     29  */
     30 public class ParcelableCallUtils {
     31     private static final int CALL_STATE_OVERRIDE_NONE = -1;
     32 
     33     public static class Converter {
     34         public ParcelableCall toParcelableCall(Call call, boolean includeVideoProvider,
     35                 PhoneAccountRegistrar phoneAccountRegistrar) {
     36             return ParcelableCallUtils.toParcelableCall(
     37                     call, includeVideoProvider, phoneAccountRegistrar, false);
     38         }
     39     }
     40 
     41     /**
     42      * Parcels all information for a {@link Call} into a new {@link ParcelableCall} instance.
     43      *
     44      * @param call The {@link Call} to parcel.
     45      * @param includeVideoProvider {@code true} if the video provider should be parcelled with the
     46      *      {@link Call}, {@code false} otherwise.  Since the {@link ParcelableCall#getVideoCall()}
     47      *      method creates a {@link VideoCallImpl} instance on access it is important for the
     48      *      recipient of the {@link ParcelableCall} to know if the video provider changed.
     49      * @param phoneAccountRegistrar The {@link PhoneAccountRegistrar}.
     50      * @param supportsExternalCalls Indicates whether the call should be parcelled for an
     51      *      {@link InCallService} which supports external calls or not.
     52      */
     53     public static ParcelableCall toParcelableCall(
     54             Call call,
     55             boolean includeVideoProvider,
     56             PhoneAccountRegistrar phoneAccountRegistrar,
     57             boolean supportsExternalCalls) {
     58         return toParcelableCall(call, includeVideoProvider, phoneAccountRegistrar,
     59                 supportsExternalCalls, CALL_STATE_OVERRIDE_NONE /* overrideState */);
     60     }
     61 
     62     /**
     63      * Parcels all information for a {@link Call} into a new {@link ParcelableCall} instance.
     64      *
     65      * @param call The {@link Call} to parcel.
     66      * @param includeVideoProvider {@code true} if the video provider should be parcelled with the
     67      *      {@link Call}, {@code false} otherwise.  Since the {@link ParcelableCall#getVideoCall()}
     68      *      method creates a {@link VideoCallImpl} instance on access it is important for the
     69      *      recipient of the {@link ParcelableCall} to know if the video provider changed.
     70      * @param phoneAccountRegistrar The {@link PhoneAccountRegistrar}.
     71      * @param supportsExternalCalls Indicates whether the call should be parcelled for an
     72      *      {@link InCallService} which supports external calls or not.
     73      * @param overrideState When not {@link #CALL_STATE_OVERRIDE_NONE}, use the provided state as an
     74      *      override to whatever is defined in the call.
     75      * @return The {@link ParcelableCall} containing all call information from the {@link Call}.
     76      */
     77     public static ParcelableCall toParcelableCall(
     78             Call call,
     79             boolean includeVideoProvider,
     80             PhoneAccountRegistrar phoneAccountRegistrar,
     81             boolean supportsExternalCalls,
     82             int overrideState) {
     83         int state;
     84         if (overrideState == CALL_STATE_OVERRIDE_NONE) {
     85             state = getParcelableState(call, supportsExternalCalls);
     86         } else {
     87             state = overrideState;
     88         }
     89         int capabilities = convertConnectionToCallCapabilities(call.getConnectionCapabilities());
     90         int properties = convertConnectionToCallProperties(call.getConnectionProperties());
     91         if (call.isConference()) {
     92             properties |= android.telecom.Call.Details.PROPERTY_CONFERENCE;
     93         }
     94 
     95         if (call.isWorkCall()) {
     96             properties |= android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL;
     97         }
     98 
     99         // If this is a single-SIM device, the "default SIM" will always be the only SIM.
    100         boolean isDefaultSmsAccount = phoneAccountRegistrar != null &&
    101                 phoneAccountRegistrar.isUserSelectedSmsPhoneAccount(call.getTargetPhoneAccount());
    102         if (call.isRespondViaSmsCapable() && isDefaultSmsAccount) {
    103             capabilities |= android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT;
    104         }
    105 
    106         if (call.isEmergencyCall()) {
    107             capabilities = removeCapability(
    108                     capabilities, android.telecom.Call.Details.CAPABILITY_MUTE);
    109         }
    110 
    111         if (state == android.telecom.Call.STATE_DIALING) {
    112             capabilities = removeCapability(capabilities,
    113                     android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
    114             capabilities = removeCapability(capabilities,
    115                     android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
    116         }
    117 
    118         String parentCallId = null;
    119         Call parentCall = call.getParentCall();
    120         if (parentCall != null) {
    121             parentCallId = parentCall.getId();
    122         }
    123 
    124         long connectTimeMillis = call.getConnectTimeMillis();
    125         List<Call> childCalls = call.getChildCalls();
    126         List<String> childCallIds = new ArrayList<>();
    127         if (!childCalls.isEmpty()) {
    128             long childConnectTimeMillis = Long.MAX_VALUE;
    129             for (Call child : childCalls) {
    130                 if (child.getConnectTimeMillis() > 0) {
    131                     childConnectTimeMillis = Math.min(child.getConnectTimeMillis(),
    132                             childConnectTimeMillis);
    133                 }
    134                 childCallIds.add(child.getId());
    135             }
    136 
    137             if (childConnectTimeMillis != Long.MAX_VALUE) {
    138                 connectTimeMillis = childConnectTimeMillis;
    139             }
    140         }
    141 
    142         Uri handle = call.getHandlePresentation() == TelecomManager.PRESENTATION_ALLOWED ?
    143                 call.getHandle() : null;
    144         String callerDisplayName = call.getCallerDisplayNamePresentation() ==
    145                 TelecomManager.PRESENTATION_ALLOWED ?  call.getCallerDisplayName() : null;
    146 
    147         List<Call> conferenceableCalls = call.getConferenceableCalls();
    148         List<String> conferenceableCallIds = new ArrayList<String>(conferenceableCalls.size());
    149         for (Call otherCall : conferenceableCalls) {
    150             conferenceableCallIds.add(otherCall.getId());
    151         }
    152 
    153         return new ParcelableCall(
    154                 call.getId(),
    155                 state,
    156                 call.getDisconnectCause(),
    157                 call.getCannedSmsResponses(),
    158                 capabilities,
    159                 properties,
    160                 connectTimeMillis,
    161                 handle,
    162                 call.getHandlePresentation(),
    163                 callerDisplayName,
    164                 call.getCallerDisplayNamePresentation(),
    165                 call.getGatewayInfo(),
    166                 call.getTargetPhoneAccount(),
    167                 includeVideoProvider,
    168                 includeVideoProvider ? call.getVideoProvider() : null,
    169                 parentCallId,
    170                 childCallIds,
    171                 call.getStatusHints(),
    172                 call.getVideoState(),
    173                 conferenceableCallIds,
    174                 call.getIntentExtras(),
    175                 call.getExtras());
    176     }
    177 
    178     private static int getParcelableState(Call call, boolean supportsExternalCalls) {
    179         int state = CallState.NEW;
    180         switch (call.getState()) {
    181             case CallState.ABORTED:
    182             case CallState.DISCONNECTED:
    183                 state = android.telecom.Call.STATE_DISCONNECTED;
    184                 break;
    185             case CallState.ACTIVE:
    186                 state = android.telecom.Call.STATE_ACTIVE;
    187                 break;
    188             case CallState.CONNECTING:
    189                 state = android.telecom.Call.STATE_CONNECTING;
    190                 break;
    191             case CallState.DIALING:
    192                 state = android.telecom.Call.STATE_DIALING;
    193                 break;
    194             case CallState.PULLING:
    195                 if (supportsExternalCalls) {
    196                     // The InCallService supports external calls, so it must handle
    197                     // STATE_PULLING_CALL.
    198                     state = android.telecom.Call.STATE_PULLING_CALL;
    199                 } else {
    200                     // The InCallService does NOT support external calls, so remap
    201                     // STATE_PULLING_CALL to STATE_DIALING.  In essence, pulling a call can be seen
    202                     // as a form of dialing, so it is appropriate for InCallServices which do not
    203                     // handle external calls.
    204                     state = android.telecom.Call.STATE_DIALING;
    205                 }
    206                 break;
    207             case CallState.DISCONNECTING:
    208                 state = android.telecom.Call.STATE_DISCONNECTING;
    209                 break;
    210             case CallState.NEW:
    211                 state = android.telecom.Call.STATE_NEW;
    212                 break;
    213             case CallState.ON_HOLD:
    214                 state = android.telecom.Call.STATE_HOLDING;
    215                 break;
    216             case CallState.RINGING:
    217                 state = android.telecom.Call.STATE_RINGING;
    218                 break;
    219             case CallState.SELECT_PHONE_ACCOUNT:
    220                 state = android.telecom.Call.STATE_SELECT_PHONE_ACCOUNT;
    221                 break;
    222         }
    223 
    224         // If we are marked as 'locally disconnecting' then mark ourselves as disconnecting instead.
    225         // Unless we're disconnect*ED*, in which case leave it at that.
    226         if (call.isLocallyDisconnecting() &&
    227                 (state != android.telecom.Call.STATE_DISCONNECTED)) {
    228             state = android.telecom.Call.STATE_DISCONNECTING;
    229         }
    230         return state;
    231     }
    232 
    233     private static final int[] CONNECTION_TO_CALL_CAPABILITY = new int[] {
    234         Connection.CAPABILITY_HOLD,
    235         android.telecom.Call.Details.CAPABILITY_HOLD,
    236 
    237         Connection.CAPABILITY_SUPPORT_HOLD,
    238         android.telecom.Call.Details.CAPABILITY_SUPPORT_HOLD,
    239 
    240         Connection.CAPABILITY_MERGE_CONFERENCE,
    241         android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE,
    242 
    243         Connection.CAPABILITY_SWAP_CONFERENCE,
    244         android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE,
    245 
    246         Connection.CAPABILITY_RESPOND_VIA_TEXT,
    247         android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT,
    248 
    249         Connection.CAPABILITY_MUTE,
    250         android.telecom.Call.Details.CAPABILITY_MUTE,
    251 
    252         Connection.CAPABILITY_MANAGE_CONFERENCE,
    253         android.telecom.Call.Details.CAPABILITY_MANAGE_CONFERENCE,
    254 
    255         Connection.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
    256         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_RX,
    257 
    258         Connection.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
    259         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_TX,
    260 
    261         Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
    262         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL,
    263 
    264         Connection.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
    265         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_RX,
    266 
    267         Connection.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
    268         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_TX,
    269 
    270         Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
    271         android.telecom.Call.Details.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL,
    272 
    273         Connection.CAPABILITY_SEPARATE_FROM_CONFERENCE,
    274         android.telecom.Call.Details.CAPABILITY_SEPARATE_FROM_CONFERENCE,
    275 
    276         Connection.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
    277         android.telecom.Call.Details.CAPABILITY_DISCONNECT_FROM_CONFERENCE,
    278 
    279         Connection.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
    280         android.telecom.Call.Details.CAPABILITY_CAN_UPGRADE_TO_VIDEO,
    281 
    282         Connection.CAPABILITY_CAN_PAUSE_VIDEO,
    283         android.telecom.Call.Details.CAPABILITY_CAN_PAUSE_VIDEO,
    284 
    285         Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
    286         android.telecom.Call.Details.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
    287 
    288         Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
    289         android.telecom.Call.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
    290 
    291         Connection.CAPABILITY_CAN_PULL_CALL,
    292         android.telecom.Call.Details.CAPABILITY_CAN_PULL_CALL
    293     };
    294 
    295     private static int convertConnectionToCallCapabilities(int connectionCapabilities) {
    296         int callCapabilities = 0;
    297         for (int i = 0; i < CONNECTION_TO_CALL_CAPABILITY.length; i += 2) {
    298             if ((CONNECTION_TO_CALL_CAPABILITY[i] & connectionCapabilities) ==
    299                     CONNECTION_TO_CALL_CAPABILITY[i]) {
    300 
    301                 callCapabilities |= CONNECTION_TO_CALL_CAPABILITY[i + 1];
    302             }
    303         }
    304         return callCapabilities;
    305     }
    306 
    307     private static final int[] CONNECTION_TO_CALL_PROPERTIES = new int[] {
    308         Connection.PROPERTY_HIGH_DEF_AUDIO,
    309         android.telecom.Call.Details.PROPERTY_HIGH_DEF_AUDIO,
    310 
    311         Connection.PROPERTY_WIFI,
    312         android.telecom.Call.Details.PROPERTY_WIFI,
    313 
    314         Connection.PROPERTY_GENERIC_CONFERENCE,
    315         android.telecom.Call.Details.PROPERTY_GENERIC_CONFERENCE,
    316 
    317         Connection.PROPERTY_EMERGENCY_CALLBACK_MODE,
    318         android.telecom.Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE,
    319 
    320         Connection.PROPERTY_IS_EXTERNAL_CALL,
    321         android.telecom.Call.Details.PROPERTY_IS_EXTERNAL_CALL,
    322 
    323         Connection.PROPERTY_HAS_CDMA_VOICE_PRIVACY,
    324         android.telecom.Call.Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY
    325     };
    326 
    327     private static int convertConnectionToCallProperties(int connectionProperties) {
    328         int callProperties = 0;
    329         for (int i = 0; i < CONNECTION_TO_CALL_PROPERTIES.length; i += 2) {
    330             if ((CONNECTION_TO_CALL_PROPERTIES[i] & connectionProperties) ==
    331                     CONNECTION_TO_CALL_PROPERTIES[i]) {
    332 
    333                 callProperties |= CONNECTION_TO_CALL_PROPERTIES[i + 1];
    334             }
    335         }
    336         return callProperties;
    337     }
    338 
    339     /**
    340      * Removes the specified capability from the set of capabilities bits and returns the new set.
    341      */
    342     private static int removeCapability(int capabilities, int capability) {
    343         return capabilities & ~capability;
    344     }
    345 
    346     private ParcelableCallUtils() {}
    347 }
    348