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