blob: d20df1b9437095ded8ddc87138af408b6ca29361 [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
2 * Copyright (C) 2006 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.phone;
18
19import android.app.ActivityManager;
20import android.app.AppOpsManager;
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -070021import android.content.ComponentName;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070022import android.content.Context;
23import android.content.Intent;
Derek Tan97ebb422014-09-05 16:55:38 -070024import android.content.SharedPreferences;
Shishir Agrawal60f9c952014-06-23 12:00:43 -070025import android.content.pm.PackageManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070026import android.net.Uri;
27import android.os.AsyncResult;
28import android.os.Binder;
29import android.os.Bundle;
30import android.os.Handler;
31import android.os.Looper;
32import android.os.Message;
33import android.os.Process;
34import android.os.ServiceManager;
35import android.os.UserHandle;
Derek Tan97ebb422014-09-05 16:55:38 -070036import android.preference.PreferenceManager;
Ihab Awadf2177b72013-11-25 13:33:23 -080037import android.provider.Settings;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070038import android.telephony.CellInfo;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -070039import android.telephony.IccOpenLogicalChannelResponse;
Jake Hambye994d462014-02-03 13:10:13 -080040import android.telephony.NeighboringCellInfo;
Wink Saville5d475dd2014-10-17 15:00:58 -070041import android.telephony.RadioAccessFamily;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070042import android.telephony.ServiceState;
Wink Saville0f3b5fc2014-11-11 08:40:49 -080043import android.telephony.SubscriptionInfo;
Jeff Sharkey85190e62014-12-05 09:40:12 -080044import android.telephony.SubscriptionManager;
Ihab Awadf2177b72013-11-25 13:33:23 -080045import android.telephony.TelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070046import android.text.TextUtils;
Jeff Sharkey85190e62014-12-05 09:40:12 -080047import android.util.ArrayMap;
48import android.util.ArraySet;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070049import android.util.Log;
Jake Hambye994d462014-02-03 13:10:13 -080050import android.util.Pair;
Jeff Sharkey85190e62014-12-05 09:40:12 -080051import android.util.Slog;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070052
Andrew Lee312e8172014-10-23 17:01:36 -070053import com.android.ims.ImsManager;
Shishir Agrawal566b7612013-10-28 14:41:00 -070054import com.android.internal.telephony.CallManager;
55import com.android.internal.telephony.CommandException;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070056import com.android.internal.telephony.DefaultPhoneNotifier;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070057import com.android.internal.telephony.ITelephony;
Jake Hambye994d462014-02-03 13:10:13 -080058import com.android.internal.telephony.IccCard;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070059import com.android.internal.telephony.Phone;
Wink Saville36469e72014-06-11 15:17:00 -070060import com.android.internal.telephony.PhoneFactory;
Wink Saville5d475dd2014-10-17 15:00:58 -070061import com.android.internal.telephony.ProxyController;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070062import com.android.internal.telephony.PhoneConstants;
Wink Savilleac1bdfd2014-11-20 23:04:44 -080063import com.android.internal.telephony.SubscriptionController;
Shishir Agrawal566b7612013-10-28 14:41:00 -070064import com.android.internal.telephony.uicc.IccIoResult;
65import com.android.internal.telephony.uicc.IccUtils;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -070066import com.android.internal.telephony.uicc.UiccCard;
Shishir Agrawal566b7612013-10-28 14:41:00 -070067import com.android.internal.telephony.uicc.UiccController;
Jake Hambye994d462014-02-03 13:10:13 -080068import com.android.internal.util.HexDump;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070069
Wink Saville36469e72014-06-11 15:17:00 -070070import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
71
Santos Cordon7d4ddf62013-07-10 11:58:08 -070072import java.util.ArrayList;
Jeff Sharkey85190e62014-12-05 09:40:12 -080073import java.util.Arrays;
Jake Hambye994d462014-02-03 13:10:13 -080074import java.util.List;
Jeff Sharkey85190e62014-12-05 09:40:12 -080075import java.util.Map;
76import java.util.Objects;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070077
78/**
79 * Implementation of the ITelephony interface.
80 */
Santos Cordon117fee72014-05-16 17:56:12 -070081public class PhoneInterfaceManager extends ITelephony.Stub {
Santos Cordon7d4ddf62013-07-10 11:58:08 -070082 private static final String LOG_TAG = "PhoneInterfaceManager";
83 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
84 private static final boolean DBG_LOC = false;
Jeff Sharkey85190e62014-12-05 09:40:12 -080085 private static final boolean DBG_MERGE = false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070086
87 // Message codes used with mMainThreadHandler
88 private static final int CMD_HANDLE_PIN_MMI = 1;
89 private static final int CMD_HANDLE_NEIGHBORING_CELL = 2;
90 private static final int EVENT_NEIGHBORING_CELL_DONE = 3;
91 private static final int CMD_ANSWER_RINGING_CALL = 4;
92 private static final int CMD_END_CALL = 5; // not used yet
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -070093 private static final int CMD_TRANSMIT_APDU_LOGICAL_CHANNEL = 7;
94 private static final int EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE = 8;
Shishir Agrawal566b7612013-10-28 14:41:00 -070095 private static final int CMD_OPEN_CHANNEL = 9;
96 private static final int EVENT_OPEN_CHANNEL_DONE = 10;
97 private static final int CMD_CLOSE_CHANNEL = 11;
98 private static final int EVENT_CLOSE_CHANNEL_DONE = 12;
Jake Hambye994d462014-02-03 13:10:13 -080099 private static final int CMD_NV_READ_ITEM = 13;
100 private static final int EVENT_NV_READ_ITEM_DONE = 14;
101 private static final int CMD_NV_WRITE_ITEM = 15;
102 private static final int EVENT_NV_WRITE_ITEM_DONE = 16;
103 private static final int CMD_NV_WRITE_CDMA_PRL = 17;
104 private static final int EVENT_NV_WRITE_CDMA_PRL_DONE = 18;
105 private static final int CMD_NV_RESET_CONFIG = 19;
106 private static final int EVENT_NV_RESET_CONFIG_DONE = 20;
Jake Hamby7c27be32014-03-03 13:25:59 -0800107 private static final int CMD_GET_PREFERRED_NETWORK_TYPE = 21;
108 private static final int EVENT_GET_PREFERRED_NETWORK_TYPE_DONE = 22;
109 private static final int CMD_SET_PREFERRED_NETWORK_TYPE = 23;
110 private static final int EVENT_SET_PREFERRED_NETWORK_TYPE_DONE = 24;
Sailesh Nepal35b59452014-03-06 09:26:56 -0800111 private static final int CMD_SEND_ENVELOPE = 25;
112 private static final int EVENT_SEND_ENVELOPE_DONE = 26;
Derek Tan6b088ee2014-09-05 14:15:18 -0700113 private static final int CMD_INVOKE_OEM_RIL_REQUEST_RAW = 27;
114 private static final int EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE = 28;
115 private static final int CMD_TRANSMIT_APDU_BASIC_CHANNEL = 29;
116 private static final int EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE = 30;
117 private static final int CMD_EXCHANGE_SIM_IO = 31;
118 private static final int EVENT_EXCHANGE_SIM_IO_DONE = 32;
Shishir Agrawal76d5da92014-11-09 16:17:25 -0800119 private static final int CMD_SET_VOICEMAIL_NUMBER = 33;
120 private static final int EVENT_SET_VOICEMAIL_NUMBER_DONE = 34;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700121
122 /** The singleton instance. */
123 private static PhoneInterfaceManager sInstance;
124
Wink Saville3ab207e2014-11-20 13:07:20 -0800125 private PhoneGlobals mApp;
126 private Phone mPhone;
127 private CallManager mCM;
128 private AppOpsManager mAppOps;
129 private MainThreadHandler mMainThreadHandler;
Wink Savilleac1bdfd2014-11-20 23:04:44 -0800130 private SubscriptionController mSubscriptionController;
Wink Saville3ab207e2014-11-20 13:07:20 -0800131 private SharedPreferences mTelephonySharedPreferences;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700132
Derek Tan97ebb422014-09-05 16:55:38 -0700133 private static final String PREF_CARRIERS_ALPHATAG_PREFIX = "carrier_alphtag_";
134 private static final String PREF_CARRIERS_NUMBER_PREFIX = "carrier_number_";
Jeff Sharkey85190e62014-12-05 09:40:12 -0800135 private static final String PREF_CARRIERS_SUBSCRIBER_PREFIX = "carrier_subscriber_";
Andrew Leedf14ead2014-10-17 14:22:52 -0700136 private static final String PREF_ENABLE_VIDEO_CALLING = "enable_video_calling";
Derek Tan89e89d42014-07-08 17:00:10 -0700137
138 /**
Shishir Agrawal566b7612013-10-28 14:41:00 -0700139 * A request object to use for transmitting data to an ICC.
140 */
141 private static final class IccAPDUArgument {
142 public int channel, cla, command, p1, p2, p3;
143 public String data;
144
145 public IccAPDUArgument(int channel, int cla, int command,
146 int p1, int p2, int p3, String data) {
147 this.channel = channel;
148 this.cla = cla;
149 this.command = command;
150 this.p1 = p1;
151 this.p2 = p2;
152 this.p3 = p3;
153 this.data = data;
154 }
155 }
156
157 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700158 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
159 * request after sending. The main thread will notify the request when it is complete.
160 */
161 private static final class MainThreadRequest {
162 /** The argument to use for the request */
163 public Object argument;
164 /** The result of the request that is run on the main thread */
165 public Object result;
Shishir Agrawal76d5da92014-11-09 16:17:25 -0800166 /** The subscriber id that this request applies to. Null if default. */
167 public Integer subId;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700168
169 public MainThreadRequest(Object argument) {
170 this.argument = argument;
171 }
Shishir Agrawal76d5da92014-11-09 16:17:25 -0800172
173 public MainThreadRequest(Object argument, Integer subId) {
174 this.argument = argument;
175 this.subId = subId;
176 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700177 }
178
Sailesh Nepalcc0375f2013-11-13 09:15:18 -0800179 private static final class IncomingThirdPartyCallArgs {
180 public final ComponentName component;
181 public final String callId;
182 public final String callerDisplayName;
183
184 public IncomingThirdPartyCallArgs(ComponentName component, String callId,
185 String callerDisplayName) {
186 this.component = component;
187 this.callId = callId;
188 this.callerDisplayName = callerDisplayName;
189 }
190 }
191
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700192 /**
193 * A handler that processes messages on the main thread in the phone process. Since many
194 * of the Phone calls are not thread safe this is needed to shuttle the requests from the
195 * inbound binder threads to the main thread in the phone process. The Binder thread
196 * may provide a {@link MainThreadRequest} object in the msg.obj field that they are waiting
197 * on, which will be notified when the operation completes and will contain the result of the
198 * request.
199 *
200 * <p>If a MainThreadRequest object is provided in the msg.obj field,
201 * note that request.result must be set to something non-null for the calling thread to
202 * unblock.
203 */
204 private final class MainThreadHandler extends Handler {
205 @Override
206 public void handleMessage(Message msg) {
207 MainThreadRequest request;
208 Message onCompleted;
209 AsyncResult ar;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700210 UiccCard uiccCard = UiccController.getInstance().getUiccCard();
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700211 IccAPDUArgument iccArgument;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700212
213 switch (msg.what) {
214 case CMD_HANDLE_PIN_MMI:
215 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800216 request.result = mPhone.handlePinMmi((String) request.argument);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700217 // Wake up the requesting thread
218 synchronized (request) {
219 request.notifyAll();
220 }
221 break;
222
223 case CMD_HANDLE_NEIGHBORING_CELL:
224 request = (MainThreadRequest) msg.obj;
225 onCompleted = obtainMessage(EVENT_NEIGHBORING_CELL_DONE,
226 request);
227 mPhone.getNeighboringCids(onCompleted);
228 break;
229
230 case EVENT_NEIGHBORING_CELL_DONE:
231 ar = (AsyncResult) msg.obj;
232 request = (MainThreadRequest) ar.userObj;
233 if (ar.exception == null && ar.result != null) {
234 request.result = ar.result;
235 } else {
236 // create an empty list to notify the waiting thread
Jake Hambye994d462014-02-03 13:10:13 -0800237 request.result = new ArrayList<NeighboringCellInfo>(0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700238 }
239 // Wake up the requesting thread
240 synchronized (request) {
241 request.notifyAll();
242 }
243 break;
244
245 case CMD_ANSWER_RINGING_CALL:
Wink Saville08874612014-08-31 19:19:58 -0700246 request = (MainThreadRequest) msg.obj;
Wink Savilleb564aae2014-10-23 10:18:09 -0700247 int answer_subId = ((Integer)request.argument).intValue();
Wink Saville08874612014-08-31 19:19:58 -0700248 answerRingingCallInternal(answer_subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700249 break;
250
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700251 case CMD_END_CALL:
252 request = (MainThreadRequest) msg.obj;
Wink Savilleb564aae2014-10-23 10:18:09 -0700253 int end_subId = ((Integer)request.argument).intValue();
Wink Saville08874612014-08-31 19:19:58 -0700254 final boolean hungUp;
255 int phoneType = getPhone(end_subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700256 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
257 // CDMA: If the user presses the Power button we treat it as
258 // ending the complete call session
Wink Saville08874612014-08-31 19:19:58 -0700259 hungUp = PhoneUtils.hangupRingingAndActive(getPhone(end_subId));
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700260 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
261 // GSM: End the call as per the Phone state
262 hungUp = PhoneUtils.hangup(mCM);
263 } else {
264 throw new IllegalStateException("Unexpected phone type: " + phoneType);
265 }
266 if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up"));
267 request.result = hungUp;
268 // Wake up the requesting thread
269 synchronized (request) {
270 request.notifyAll();
271 }
272 break;
273
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700274 case CMD_TRANSMIT_APDU_LOGICAL_CHANNEL:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700275 request = (MainThreadRequest) msg.obj;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700276 iccArgument = (IccAPDUArgument) request.argument;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700277 if (uiccCard == null) {
278 loge("iccTransmitApduLogicalChannel: No UICC");
279 request.result = new IccIoResult(0x6F, 0, (byte[])null);
280 synchronized (request) {
281 request.notifyAll();
282 }
283 } else {
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700284 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE,
285 request);
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700286 uiccCard.iccTransmitApduLogicalChannel(
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700287 iccArgument.channel, iccArgument.cla, iccArgument.command,
288 iccArgument.p1, iccArgument.p2, iccArgument.p3, iccArgument.data,
Shishir Agrawal566b7612013-10-28 14:41:00 -0700289 onCompleted);
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700290 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700291 break;
292
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700293 case EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700294 ar = (AsyncResult) msg.obj;
295 request = (MainThreadRequest) ar.userObj;
296 if (ar.exception == null && ar.result != null) {
297 request.result = ar.result;
298 } else {
299 request.result = new IccIoResult(0x6F, 0, (byte[])null);
300 if (ar.result == null) {
301 loge("iccTransmitApduLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800302 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700303 loge("iccTransmitApduLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800304 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700305 } else {
306 loge("iccTransmitApduLogicalChannel: Unknown exception");
307 }
308 }
309 synchronized (request) {
310 request.notifyAll();
311 }
312 break;
313
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700314 case CMD_TRANSMIT_APDU_BASIC_CHANNEL:
315 request = (MainThreadRequest) msg.obj;
316 iccArgument = (IccAPDUArgument) request.argument;
317 if (uiccCard == null) {
318 loge("iccTransmitApduBasicChannel: No UICC");
319 request.result = new IccIoResult(0x6F, 0, (byte[])null);
320 synchronized (request) {
321 request.notifyAll();
322 }
323 } else {
324 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE,
325 request);
326 uiccCard.iccTransmitApduBasicChannel(
327 iccArgument.cla, iccArgument.command, iccArgument.p1, iccArgument.p2,
328 iccArgument.p3, iccArgument.data, onCompleted);
329 }
330 break;
331
332 case EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE:
333 ar = (AsyncResult) msg.obj;
334 request = (MainThreadRequest) ar.userObj;
335 if (ar.exception == null && ar.result != null) {
336 request.result = ar.result;
337 } else {
338 request.result = new IccIoResult(0x6F, 0, (byte[])null);
339 if (ar.result == null) {
340 loge("iccTransmitApduBasicChannel: Empty response");
341 } else if (ar.exception instanceof CommandException) {
342 loge("iccTransmitApduBasicChannel: CommandException: " +
343 ar.exception);
344 } else {
345 loge("iccTransmitApduBasicChannel: Unknown exception");
346 }
347 }
348 synchronized (request) {
349 request.notifyAll();
350 }
351 break;
352
353 case CMD_EXCHANGE_SIM_IO:
354 request = (MainThreadRequest) msg.obj;
355 iccArgument = (IccAPDUArgument) request.argument;
356 if (uiccCard == null) {
357 loge("iccExchangeSimIO: No UICC");
358 request.result = new IccIoResult(0x6F, 0, (byte[])null);
359 synchronized (request) {
360 request.notifyAll();
361 }
362 } else {
363 onCompleted = obtainMessage(EVENT_EXCHANGE_SIM_IO_DONE,
364 request);
365 uiccCard.iccExchangeSimIO(iccArgument.cla, /* fileID */
366 iccArgument.command, iccArgument.p1, iccArgument.p2, iccArgument.p3,
367 iccArgument.data, onCompleted);
368 }
369 break;
370
371 case EVENT_EXCHANGE_SIM_IO_DONE:
372 ar = (AsyncResult) msg.obj;
373 request = (MainThreadRequest) ar.userObj;
374 if (ar.exception == null && ar.result != null) {
375 request.result = ar.result;
376 } else {
377 request.result = new IccIoResult(0x6f, 0, (byte[])null);
378 }
379 synchronized (request) {
380 request.notifyAll();
381 }
382 break;
383
Derek Tan4d5e5c12014-02-04 11:54:58 -0800384 case CMD_SEND_ENVELOPE:
385 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700386 if (uiccCard == null) {
387 loge("sendEnvelopeWithStatus: No UICC");
388 request.result = new IccIoResult(0x6F, 0, (byte[])null);
389 synchronized (request) {
390 request.notifyAll();
391 }
392 } else {
393 onCompleted = obtainMessage(EVENT_SEND_ENVELOPE_DONE, request);
394 uiccCard.sendEnvelopeWithStatus((String)request.argument, onCompleted);
395 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800396 break;
397
398 case EVENT_SEND_ENVELOPE_DONE:
399 ar = (AsyncResult) msg.obj;
400 request = (MainThreadRequest) ar.userObj;
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700401 if (ar.exception == null && ar.result != null) {
402 request.result = ar.result;
Derek Tan4d5e5c12014-02-04 11:54:58 -0800403 } else {
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700404 request.result = new IccIoResult(0x6F, 0, (byte[])null);
405 if (ar.result == null) {
406 loge("sendEnvelopeWithStatus: Empty response");
407 } else if (ar.exception instanceof CommandException) {
408 loge("sendEnvelopeWithStatus: CommandException: " +
409 ar.exception);
410 } else {
411 loge("sendEnvelopeWithStatus: exception:" + ar.exception);
412 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800413 }
414 synchronized (request) {
415 request.notifyAll();
416 }
417 break;
418
Shishir Agrawal566b7612013-10-28 14:41:00 -0700419 case CMD_OPEN_CHANNEL:
420 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700421 if (uiccCard == null) {
422 loge("iccOpenLogicalChannel: No UICC");
423 request.result = new IccIoResult(0x6F, 0, (byte[])null);
424 synchronized (request) {
425 request.notifyAll();
426 }
427 } else {
428 onCompleted = obtainMessage(EVENT_OPEN_CHANNEL_DONE, request);
429 uiccCard.iccOpenLogicalChannel((String)request.argument, onCompleted);
430 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700431 break;
432
433 case EVENT_OPEN_CHANNEL_DONE:
434 ar = (AsyncResult) msg.obj;
435 request = (MainThreadRequest) ar.userObj;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700436 IccOpenLogicalChannelResponse openChannelResp;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700437 if (ar.exception == null && ar.result != null) {
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700438 int[] result = (int[]) ar.result;
439 int channelId = result[0];
440 byte[] selectResponse = null;
441 if (result.length > 1) {
442 selectResponse = new byte[result.length - 1];
443 for (int i = 1; i < result.length; ++i) {
444 selectResponse[i - 1] = (byte) result[i];
445 }
446 }
447 openChannelResp = new IccOpenLogicalChannelResponse(channelId,
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700448 IccOpenLogicalChannelResponse.STATUS_NO_ERROR, selectResponse);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700449 } else {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700450 if (ar.result == null) {
451 loge("iccOpenLogicalChannel: Empty response");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700452 }
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700453 if (ar.exception != null) {
454 loge("iccOpenLogicalChannel: Exception: " + ar.exception);
455 }
456
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700457 int errorCode = IccOpenLogicalChannelResponse.STATUS_UNKNOWN_ERROR;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700458 if ((ar.exception != null) && (ar.exception instanceof CommandException)) {
459 if (ar.exception.getMessage().compareTo("MISSING_RESOURCE") == 0) {
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700460 errorCode = IccOpenLogicalChannelResponse.STATUS_MISSING_RESOURCE;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700461 } else if (ar.exception.getMessage().compareTo("NO_SUCH_ELEMENT") == 0) {
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700462 errorCode = IccOpenLogicalChannelResponse.STATUS_NO_SUCH_ELEMENT;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700463 }
464 }
465 openChannelResp = new IccOpenLogicalChannelResponse(
466 IccOpenLogicalChannelResponse.INVALID_CHANNEL, errorCode, null);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700467 }
Shishir Agrawal82c8a462014-07-31 18:13:17 -0700468 request.result = openChannelResp;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700469 synchronized (request) {
470 request.notifyAll();
471 }
472 break;
473
474 case CMD_CLOSE_CHANNEL:
475 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700476 if (uiccCard == null) {
477 loge("iccCloseLogicalChannel: No UICC");
478 request.result = new IccIoResult(0x6F, 0, (byte[])null);
479 synchronized (request) {
480 request.notifyAll();
481 }
482 } else {
483 onCompleted = obtainMessage(EVENT_CLOSE_CHANNEL_DONE, request);
484 uiccCard.iccCloseLogicalChannel((Integer) request.argument, onCompleted);
485 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700486 break;
487
488 case EVENT_CLOSE_CHANNEL_DONE:
Jake Hambye994d462014-02-03 13:10:13 -0800489 handleNullReturnEvent(msg, "iccCloseLogicalChannel");
490 break;
491
492 case CMD_NV_READ_ITEM:
493 request = (MainThreadRequest) msg.obj;
494 onCompleted = obtainMessage(EVENT_NV_READ_ITEM_DONE, request);
495 mPhone.nvReadItem((Integer) request.argument, onCompleted);
496 break;
497
498 case EVENT_NV_READ_ITEM_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700499 ar = (AsyncResult) msg.obj;
500 request = (MainThreadRequest) ar.userObj;
Jake Hambye994d462014-02-03 13:10:13 -0800501 if (ar.exception == null && ar.result != null) {
502 request.result = ar.result; // String
Shishir Agrawal566b7612013-10-28 14:41:00 -0700503 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800504 request.result = "";
505 if (ar.result == null) {
506 loge("nvReadItem: Empty response");
507 } else if (ar.exception instanceof CommandException) {
508 loge("nvReadItem: CommandException: " +
509 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700510 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800511 loge("nvReadItem: Unknown exception");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700512 }
513 }
514 synchronized (request) {
515 request.notifyAll();
516 }
517 break;
518
Jake Hambye994d462014-02-03 13:10:13 -0800519 case CMD_NV_WRITE_ITEM:
520 request = (MainThreadRequest) msg.obj;
521 onCompleted = obtainMessage(EVENT_NV_WRITE_ITEM_DONE, request);
522 Pair<Integer, String> idValue = (Pair<Integer, String>) request.argument;
523 mPhone.nvWriteItem(idValue.first, idValue.second, onCompleted);
524 break;
525
526 case EVENT_NV_WRITE_ITEM_DONE:
527 handleNullReturnEvent(msg, "nvWriteItem");
528 break;
529
530 case CMD_NV_WRITE_CDMA_PRL:
531 request = (MainThreadRequest) msg.obj;
532 onCompleted = obtainMessage(EVENT_NV_WRITE_CDMA_PRL_DONE, request);
533 mPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
534 break;
535
536 case EVENT_NV_WRITE_CDMA_PRL_DONE:
537 handleNullReturnEvent(msg, "nvWriteCdmaPrl");
538 break;
539
540 case CMD_NV_RESET_CONFIG:
541 request = (MainThreadRequest) msg.obj;
542 onCompleted = obtainMessage(EVENT_NV_RESET_CONFIG_DONE, request);
543 mPhone.nvResetConfig((Integer) request.argument, onCompleted);
544 break;
545
546 case EVENT_NV_RESET_CONFIG_DONE:
547 handleNullReturnEvent(msg, "nvResetConfig");
548 break;
549
Jake Hamby7c27be32014-03-03 13:25:59 -0800550 case CMD_GET_PREFERRED_NETWORK_TYPE:
551 request = (MainThreadRequest) msg.obj;
552 onCompleted = obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE_DONE, request);
553 mPhone.getPreferredNetworkType(onCompleted);
554 break;
555
556 case EVENT_GET_PREFERRED_NETWORK_TYPE_DONE:
557 ar = (AsyncResult) msg.obj;
558 request = (MainThreadRequest) ar.userObj;
559 if (ar.exception == null && ar.result != null) {
560 request.result = ar.result; // Integer
561 } else {
562 request.result = -1;
563 if (ar.result == null) {
564 loge("getPreferredNetworkType: Empty response");
565 } else if (ar.exception instanceof CommandException) {
566 loge("getPreferredNetworkType: CommandException: " +
567 ar.exception);
568 } else {
569 loge("getPreferredNetworkType: Unknown exception");
570 }
571 }
572 synchronized (request) {
573 request.notifyAll();
574 }
575 break;
576
577 case CMD_SET_PREFERRED_NETWORK_TYPE:
578 request = (MainThreadRequest) msg.obj;
579 onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);
580 int networkType = (Integer) request.argument;
581 mPhone.setPreferredNetworkType(networkType, onCompleted);
582 break;
583
584 case EVENT_SET_PREFERRED_NETWORK_TYPE_DONE:
585 handleNullReturnEvent(msg, "setPreferredNetworkType");
586 break;
587
Steven Liu4bf01bc2014-07-17 11:05:29 -0500588 case CMD_INVOKE_OEM_RIL_REQUEST_RAW:
589 request = (MainThreadRequest)msg.obj;
590 onCompleted = obtainMessage(EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE, request);
591 mPhone.invokeOemRilRequestRaw((byte[])request.argument, onCompleted);
592 break;
593
594 case EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE:
595 ar = (AsyncResult)msg.obj;
596 request = (MainThreadRequest)ar.userObj;
597 request.result = ar;
598 synchronized (request) {
599 request.notifyAll();
600 }
601 break;
602
Shishir Agrawal76d5da92014-11-09 16:17:25 -0800603 case CMD_SET_VOICEMAIL_NUMBER:
604 request = (MainThreadRequest) msg.obj;
605 onCompleted = obtainMessage(EVENT_SET_VOICEMAIL_NUMBER_DONE, request);
606 Pair<String, String> tagNum = (Pair<String, String>) request.argument;
607 Phone phone = (request.subId == null) ? mPhone : getPhone(request.subId);
608 phone.setVoiceMailNumber(tagNum.first, tagNum.second, onCompleted);
609 break;
610
611 case EVENT_SET_VOICEMAIL_NUMBER_DONE:
612 handleNullReturnEvent(msg, "setVoicemailNumber");
613 break;
614
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700615 default:
616 Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
617 break;
618 }
619 }
Jake Hambye994d462014-02-03 13:10:13 -0800620
621 private void handleNullReturnEvent(Message msg, String command) {
622 AsyncResult ar = (AsyncResult) msg.obj;
623 MainThreadRequest request = (MainThreadRequest) ar.userObj;
624 if (ar.exception == null) {
625 request.result = true;
626 } else {
627 request.result = false;
628 if (ar.exception instanceof CommandException) {
629 loge(command + ": CommandException: " + ar.exception);
630 } else {
631 loge(command + ": Unknown exception");
632 }
633 }
634 synchronized (request) {
635 request.notifyAll();
636 }
637 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700638 }
639
640 /**
641 * Posts the specified command to be executed on the main thread,
642 * waits for the request to complete, and returns the result.
643 * @see #sendRequestAsync
644 */
645 private Object sendRequest(int command, Object argument) {
Santos Cordon500b0e02014-06-17 10:33:33 -0700646 return sendRequest(command, argument, null);
Wink Saville36469e72014-06-11 15:17:00 -0700647 }
648
649 /**
650 * Posts the specified command to be executed on the main thread,
651 * waits for the request to complete, and returns the result.
652 * @see #sendRequestAsync
653 */
Shishir Agrawal76d5da92014-11-09 16:17:25 -0800654 private Object sendRequest(int command, Object argument, Integer subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700655 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
656 throw new RuntimeException("This method will deadlock if called from the main thread.");
657 }
658
Shishir Agrawal76d5da92014-11-09 16:17:25 -0800659 MainThreadRequest request = new MainThreadRequest(argument, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700660 Message msg = mMainThreadHandler.obtainMessage(command, request);
661 msg.sendToTarget();
662
663 // Wait for the request to complete
664 synchronized (request) {
665 while (request.result == null) {
666 try {
667 request.wait();
668 } catch (InterruptedException e) {
669 // Do nothing, go back and wait until the request is complete
670 }
671 }
672 }
673 return request.result;
674 }
675
676 /**
677 * Asynchronous ("fire and forget") version of sendRequest():
678 * Posts the specified command to be executed on the main thread, and
679 * returns immediately.
680 * @see #sendRequest
681 */
682 private void sendRequestAsync(int command) {
683 mMainThreadHandler.sendEmptyMessage(command);
684 }
685
686 /**
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -0700687 * Same as {@link #sendRequestAsync(int)} except it takes an argument.
688 * @see {@link #sendRequest(int,Object)}
689 */
690 private void sendRequestAsync(int command, Object argument) {
691 MainThreadRequest request = new MainThreadRequest(argument);
692 Message msg = mMainThreadHandler.obtainMessage(command, request);
693 msg.sendToTarget();
694 }
695
696 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700697 * Initialize the singleton PhoneInterfaceManager instance.
698 * This is only done once, at startup, from PhoneApp.onCreate().
699 */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700700 /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700701 synchronized (PhoneInterfaceManager.class) {
702 if (sInstance == null) {
Sailesh Nepal194161e2014-07-03 08:57:44 -0700703 sInstance = new PhoneInterfaceManager(app, phone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700704 } else {
705 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
706 }
707 return sInstance;
708 }
709 }
710
711 /** Private constructor; @see init() */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700712 private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700713 mApp = app;
714 mPhone = phone;
715 mCM = PhoneGlobals.getInstance().mCM;
716 mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
717 mMainThreadHandler = new MainThreadHandler();
Andrew Leedf14ead2014-10-17 14:22:52 -0700718 mTelephonySharedPreferences =
Derek Tan97ebb422014-09-05 16:55:38 -0700719 PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
Wink Savilleac1bdfd2014-11-20 23:04:44 -0800720 mSubscriptionController = SubscriptionController.getInstance();
Wink Saville3ab207e2014-11-20 13:07:20 -0800721
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700722 publish();
723 }
724
725 private void publish() {
726 if (DBG) log("publish: " + this);
727
728 ServiceManager.addService("phone", this);
729 }
730
Wink Saville36469e72014-06-11 15:17:00 -0700731 // returns phone associated with the subId.
Wink Savilleb564aae2014-10-23 10:18:09 -0700732 private Phone getPhone(int subId) {
Wink Savilleac1bdfd2014-11-20 23:04:44 -0800733 return PhoneFactory.getPhone(mSubscriptionController.getPhoneId(subId));
Wink Saville36469e72014-06-11 15:17:00 -0700734 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700735 //
736 // Implementation of the ITelephony interface.
737 //
738
739 public void dial(String number) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700740 dialForSubscriber(getPreferredVoiceSubscription(), number);
Wink Saville36469e72014-06-11 15:17:00 -0700741 }
742
Wink Savilleb564aae2014-10-23 10:18:09 -0700743 public void dialForSubscriber(int subId, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700744 if (DBG) log("dial: " + number);
745 // No permission check needed here: This is just a wrapper around the
746 // ACTION_DIAL intent, which is available to any app since it puts up
747 // the UI before it does anything.
748
749 String url = createTelUrl(number);
750 if (url == null) {
751 return;
752 }
753
754 // PENDING: should we just silently fail if phone is offhook or ringing?
Wink Saville36469e72014-06-11 15:17:00 -0700755 PhoneConstants.State state = mCM.getState(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700756 if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
757 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
758 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
759 mApp.startActivity(intent);
760 }
761 }
762
763 public void call(String callingPackage, String number) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700764 callForSubscriber(getPreferredVoiceSubscription(), callingPackage, number);
Wink Saville36469e72014-06-11 15:17:00 -0700765 }
766
Wink Savilleb564aae2014-10-23 10:18:09 -0700767 public void callForSubscriber(int subId, String callingPackage, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700768 if (DBG) log("call: " + number);
769
770 // This is just a wrapper around the ACTION_CALL intent, but we still
771 // need to do a permission check since we're calling startActivity()
772 // from the context of the phone app.
773 enforceCallPermission();
774
775 if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
776 != AppOpsManager.MODE_ALLOWED) {
777 return;
778 }
779
780 String url = createTelUrl(number);
781 if (url == null) {
782 return;
783 }
784
Wink Saville08874612014-08-31 19:19:58 -0700785 boolean isValid = false;
Wink Savilleac1bdfd2014-11-20 23:04:44 -0800786 List<SubscriptionInfo> slist = mSubscriptionController.getActiveSubscriptionInfoList();
Wink Saville3ab207e2014-11-20 13:07:20 -0800787 if (slist != null) {
788 for (SubscriptionInfo subInfoRecord : slist) {
789 if (subInfoRecord.getSubscriptionId() == subId) {
790 isValid = true;
791 break;
792 }
Wink Saville08874612014-08-31 19:19:58 -0700793 }
794 }
795 if (isValid == false) {
796 return;
797 }
798
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700799 Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
Wink Saville36469e72014-06-11 15:17:00 -0700800 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700801 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
802 mApp.startActivity(intent);
803 }
804
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700805 /**
806 * End a call based on call state
807 * @return true is a call was ended
808 */
809 public boolean endCall() {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700810 return endCallForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -0700811 }
812
813 /**
814 * End a call based on the call state of the subId
815 * @return true is a call was ended
816 */
Wink Savilleb564aae2014-10-23 10:18:09 -0700817 public boolean endCallForSubscriber(int subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700818 enforceCallPermission();
Wink Saville9f73bda2014-11-05 08:13:36 -0800819 return (Boolean) sendRequest(CMD_END_CALL, new Integer(subId), null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700820 }
821
822 public void answerRingingCall() {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700823 answerRingingCallForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -0700824 }
825
Wink Savilleb564aae2014-10-23 10:18:09 -0700826 public void answerRingingCallForSubscriber(int subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700827 if (DBG) log("answerRingingCall...");
828 // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
829 // but that can probably wait till the big TelephonyManager API overhaul.
830 // For now, protect this call with the MODIFY_PHONE_STATE permission.
831 enforceModifyPermission();
Wink Saville9f73bda2014-11-05 08:13:36 -0800832 sendRequest(CMD_ANSWER_RINGING_CALL, new Integer(subId), null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700833 }
834
835 /**
836 * Make the actual telephony calls to implement answerRingingCall().
837 * This should only be called from the main thread of the Phone app.
838 * @see #answerRingingCall
839 *
840 * TODO: it would be nice to return true if we answered the call, or
841 * false if there wasn't actually a ringing incoming call, or some
842 * other error occurred. (In other words, pass back the return value
843 * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
844 * But that would require calling this method via sendRequest() rather
845 * than sendRequestAsync(), and right now we don't actually *need* that
846 * return value, so let's just return void for now.
847 */
Wink Savilleb564aae2014-10-23 10:18:09 -0700848 private void answerRingingCallInternal(int subId) {
Wink Saville08874612014-08-31 19:19:58 -0700849 final boolean hasRingingCall = !getPhone(subId).getRingingCall().isIdle();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700850 if (hasRingingCall) {
Wink Saville08874612014-08-31 19:19:58 -0700851 final boolean hasActiveCall = !getPhone(subId).getForegroundCall().isIdle();
852 final boolean hasHoldingCall = !getPhone(subId).getBackgroundCall().isIdle();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700853 if (hasActiveCall && hasHoldingCall) {
854 // Both lines are in use!
855 // TODO: provide a flag to let the caller specify what
856 // policy to use if both lines are in use. (The current
857 // behavior is hardwired to "answer incoming, end ongoing",
858 // which is how the CALL button is specced to behave.)
859 PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
860 return;
861 } else {
862 // answerCall() will automatically hold the current active
863 // call, if there is one.
864 PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
865 return;
866 }
867 } else {
868 // No call was ringing.
869 return;
870 }
871 }
872
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700873 /**
Santos Cordon5422a8d2014-09-12 04:20:56 -0700874 * This method is no longer used and can be removed once TelephonyManager stops referring to it.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700875 */
Santos Cordon5422a8d2014-09-12 04:20:56 -0700876 public void silenceRinger() {
877 Log.e(LOG_TAG, "silenseRinger not supported");
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700878 }
879
880 public boolean isOffhook() {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700881 return isOffhookForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -0700882 }
883
Wink Savilleb564aae2014-10-23 10:18:09 -0700884 public boolean isOffhookForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -0700885 return (getPhone(subId).getState() == PhoneConstants.State.OFFHOOK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700886 }
887
888 public boolean isRinging() {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700889 return (isRingingForSubscriber(getDefaultSubscription()));
Wink Saville36469e72014-06-11 15:17:00 -0700890 }
891
Wink Savilleb564aae2014-10-23 10:18:09 -0700892 public boolean isRingingForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -0700893 return (getPhone(subId).getState() == PhoneConstants.State.RINGING);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700894 }
895
896 public boolean isIdle() {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700897 return isIdleForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -0700898 }
899
Wink Savilleb564aae2014-10-23 10:18:09 -0700900 public boolean isIdleForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -0700901 return (getPhone(subId).getState() == PhoneConstants.State.IDLE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700902 }
903
904 public boolean isSimPinEnabled() {
905 enforceReadPermission();
906 return (PhoneGlobals.getInstance().isSimPinEnabled());
907 }
908
909 public boolean supplyPin(String pin) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700910 return supplyPinForSubscriber(getDefaultSubscription(), pin);
Wink Saville36469e72014-06-11 15:17:00 -0700911 }
912
Wink Savilleb564aae2014-10-23 10:18:09 -0700913 public boolean supplyPinForSubscriber(int subId, String pin) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700914 int [] resultArray = supplyPinReportResultForSubscriber(subId, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700915 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
916 }
917
918 public boolean supplyPuk(String puk, String pin) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700919 return supplyPukForSubscriber(getDefaultSubscription(), puk, pin);
Wink Saville36469e72014-06-11 15:17:00 -0700920 }
921
Wink Savilleb564aae2014-10-23 10:18:09 -0700922 public boolean supplyPukForSubscriber(int subId, String puk, String pin) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700923 int [] resultArray = supplyPukReportResultForSubscriber(subId, puk, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700924 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
925 }
926
927 /** {@hide} */
928 public int[] supplyPinReportResult(String pin) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700929 return supplyPinReportResultForSubscriber(getDefaultSubscription(), pin);
Wink Saville36469e72014-06-11 15:17:00 -0700930 }
931
Wink Savilleb564aae2014-10-23 10:18:09 -0700932 public int[] supplyPinReportResultForSubscriber(int subId, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700933 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700934 final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700935 checkSimPin.start();
936 return checkSimPin.unlockSim(null, pin);
937 }
938
Wink Saville9de0f752013-10-22 19:04:03 -0700939 /** {@hide} */
940 public int[] supplyPukReportResult(String puk, String pin) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700941 return supplyPukReportResultForSubscriber(getDefaultSubscription(), puk, pin);
Wink Saville36469e72014-06-11 15:17:00 -0700942 }
943
Wink Savilleb564aae2014-10-23 10:18:09 -0700944 public int[] supplyPukReportResultForSubscriber(int subId, String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700945 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700946 final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700947 checkSimPuk.start();
948 return checkSimPuk.unlockSim(puk, pin);
949 }
950
951 /**
Wink Saville9de0f752013-10-22 19:04:03 -0700952 * Helper thread to turn async call to SimCard#supplyPin into
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700953 * a synchronous one.
954 */
955 private static class UnlockSim extends Thread {
956
957 private final IccCard mSimCard;
958
959 private boolean mDone = false;
Wink Saville9de0f752013-10-22 19:04:03 -0700960 private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
961 private int mRetryCount = -1;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700962
963 // For replies from SimCard interface
964 private Handler mHandler;
965
966 // For async handler to identify request type
967 private static final int SUPPLY_PIN_COMPLETE = 100;
968
969 public UnlockSim(IccCard simCard) {
970 mSimCard = simCard;
971 }
972
973 @Override
974 public void run() {
975 Looper.prepare();
976 synchronized (UnlockSim.this) {
977 mHandler = new Handler() {
978 @Override
979 public void handleMessage(Message msg) {
980 AsyncResult ar = (AsyncResult) msg.obj;
981 switch (msg.what) {
982 case SUPPLY_PIN_COMPLETE:
983 Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
984 synchronized (UnlockSim.this) {
Wink Saville9de0f752013-10-22 19:04:03 -0700985 mRetryCount = msg.arg1;
986 if (ar.exception != null) {
987 if (ar.exception instanceof CommandException &&
988 ((CommandException)(ar.exception)).getCommandError()
989 == CommandException.Error.PASSWORD_INCORRECT) {
990 mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
991 } else {
992 mResult = PhoneConstants.PIN_GENERAL_FAILURE;
993 }
994 } else {
995 mResult = PhoneConstants.PIN_RESULT_SUCCESS;
996 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700997 mDone = true;
998 UnlockSim.this.notifyAll();
999 }
1000 break;
1001 }
1002 }
1003 };
1004 UnlockSim.this.notifyAll();
1005 }
1006 Looper.loop();
1007 }
1008
1009 /*
1010 * Use PIN or PUK to unlock SIM card
1011 *
1012 * If PUK is null, unlock SIM card with PIN
1013 *
1014 * If PUK is not null, unlock SIM card with PUK and set PIN code
1015 */
Wink Saville9de0f752013-10-22 19:04:03 -07001016 synchronized int[] unlockSim(String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001017
1018 while (mHandler == null) {
1019 try {
1020 wait();
1021 } catch (InterruptedException e) {
1022 Thread.currentThread().interrupt();
1023 }
1024 }
1025 Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
1026
1027 if (puk == null) {
1028 mSimCard.supplyPin(pin, callback);
1029 } else {
1030 mSimCard.supplyPuk(puk, pin, callback);
1031 }
1032
1033 while (!mDone) {
1034 try {
1035 Log.d(LOG_TAG, "wait for done");
1036 wait();
1037 } catch (InterruptedException e) {
1038 // Restore the interrupted status
1039 Thread.currentThread().interrupt();
1040 }
1041 }
1042 Log.d(LOG_TAG, "done");
Wink Saville9de0f752013-10-22 19:04:03 -07001043 int[] resultArray = new int[2];
1044 resultArray[0] = mResult;
1045 resultArray[1] = mRetryCount;
1046 return resultArray;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001047 }
1048 }
1049
1050 public void updateServiceLocation() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001051 updateServiceLocationForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001052
1053 }
1054
Wink Savilleb564aae2014-10-23 10:18:09 -07001055 public void updateServiceLocationForSubscriber(int subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001056 // No permission check needed here: this call is harmless, and it's
1057 // needed for the ServiceState.requestStateUpdate() call (which is
1058 // already intentionally exposed to 3rd parties.)
Wink Saville36469e72014-06-11 15:17:00 -07001059 getPhone(subId).updateServiceLocation();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001060 }
1061
1062 public boolean isRadioOn() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001063 return isRadioOnForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001064 }
1065
Wink Savilleb564aae2014-10-23 10:18:09 -07001066 public boolean isRadioOnForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001067 return getPhone(subId).getServiceState().getState() != ServiceState.STATE_POWER_OFF;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001068 }
1069
1070 public void toggleRadioOnOff() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001071 toggleRadioOnOffForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001072
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001073 }
Wink Saville36469e72014-06-11 15:17:00 -07001074
Wink Savilleb564aae2014-10-23 10:18:09 -07001075 public void toggleRadioOnOffForSubscriber(int subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001076 enforceModifyPermission();
Wink Savilleadd7cc52014-09-08 14:23:09 -07001077 getPhone(subId).setRadioPower(!isRadioOnForSubscriber(subId));
Wink Saville36469e72014-06-11 15:17:00 -07001078 }
1079
1080 public boolean setRadio(boolean turnOn) {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001081 return setRadioForSubscriber(getDefaultSubscription(), turnOn);
Wink Saville36469e72014-06-11 15:17:00 -07001082 }
1083
Wink Savilleb564aae2014-10-23 10:18:09 -07001084 public boolean setRadioForSubscriber(int subId, boolean turnOn) {
Wink Saville36469e72014-06-11 15:17:00 -07001085 enforceModifyPermission();
1086 if ((getPhone(subId).getServiceState().getState() !=
1087 ServiceState.STATE_POWER_OFF) != turnOn) {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001088 toggleRadioOnOffForSubscriber(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001089 }
1090 return true;
1091 }
Wink Saville36469e72014-06-11 15:17:00 -07001092
Naveen Kalla1fd79bd2014-08-08 00:48:59 -07001093 public boolean needMobileRadioShutdown() {
1094 /*
1095 * If any of the Radios are available, it will need to be
1096 * shutdown. So return true if any Radio is available.
1097 */
1098 for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
1099 Phone phone = PhoneFactory.getPhone(i);
1100 if (phone != null && phone.isRadioAvailable()) return true;
1101 }
1102 logv(TelephonyManager.getDefault().getPhoneCount() + " Phones are shutdown.");
1103 return false;
1104 }
1105
1106 public void shutdownMobileRadios() {
1107 for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
1108 logv("Shutting down Phone " + i);
1109 shutdownRadioUsingPhoneId(i);
1110 }
1111 }
1112
1113 private void shutdownRadioUsingPhoneId(int phoneId) {
1114 enforceModifyPermission();
1115 Phone phone = PhoneFactory.getPhone(phoneId);
1116 if (phone != null && phone.isRadioAvailable()) {
1117 phone.shutdownRadio();
1118 }
1119 }
1120
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001121 public boolean setRadioPower(boolean turnOn) {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001122 return setRadioPowerForSubscriber(getDefaultSubscription(), turnOn);
Wink Saville36469e72014-06-11 15:17:00 -07001123 }
1124
Wink Savilleb564aae2014-10-23 10:18:09 -07001125 public boolean setRadioPowerForSubscriber(int subId, boolean turnOn) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001126 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001127 getPhone(subId).setRadioPower(turnOn);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001128 return true;
1129 }
1130
Wink Saville36469e72014-06-11 15:17:00 -07001131 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001132 public boolean enableDataConnectivity() {
1133 enforceModifyPermission();
Wink Savilleac1bdfd2014-11-20 23:04:44 -08001134 int subId = mSubscriptionController.getDefaultDataSubId();
Wink Saville36469e72014-06-11 15:17:00 -07001135 getPhone(subId).setDataEnabled(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001136 return true;
1137 }
1138
Wink Saville36469e72014-06-11 15:17:00 -07001139 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001140 public boolean disableDataConnectivity() {
1141 enforceModifyPermission();
Wink Savilleac1bdfd2014-11-20 23:04:44 -08001142 int subId = mSubscriptionController.getDefaultDataSubId();
Wink Saville36469e72014-06-11 15:17:00 -07001143 getPhone(subId).setDataEnabled(false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001144 return true;
1145 }
1146
Wink Saville36469e72014-06-11 15:17:00 -07001147 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001148 public boolean isDataConnectivityPossible() {
Wink Savilleac1bdfd2014-11-20 23:04:44 -08001149 int subId = mSubscriptionController.getDefaultDataSubId();
Wink Saville36469e72014-06-11 15:17:00 -07001150 return getPhone(subId).isDataConnectivityPossible();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001151 }
1152
1153 public boolean handlePinMmi(String dialString) {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001154 return handlePinMmiForSubscriber(getDefaultSubscription(), dialString);
Wink Saville36469e72014-06-11 15:17:00 -07001155 }
1156
Wink Savilleb564aae2014-10-23 10:18:09 -07001157 public boolean handlePinMmiForSubscriber(int subId, String dialString) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001158 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001159 return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001160 }
1161
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001162 public int getCallState() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001163 return getCallStateForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001164 }
1165
Wink Savilleb564aae2014-10-23 10:18:09 -07001166 public int getCallStateForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001167 return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001168 }
1169
1170 public int getDataState() {
Wink Savilleac1bdfd2014-11-20 23:04:44 -08001171 Phone phone = getPhone(mSubscriptionController.getDefaultDataSubId());
Wink Saville36469e72014-06-11 15:17:00 -07001172 return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001173 }
1174
1175 public int getDataActivity() {
Wink Savilleac1bdfd2014-11-20 23:04:44 -08001176 Phone phone = getPhone(mSubscriptionController.getDefaultDataSubId());
Wink Saville36469e72014-06-11 15:17:00 -07001177 return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001178 }
1179
1180 @Override
1181 public Bundle getCellLocation() {
1182 try {
1183 mApp.enforceCallingOrSelfPermission(
1184 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1185 } catch (SecurityException e) {
1186 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1187 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1188 // is the weaker precondition
1189 mApp.enforceCallingOrSelfPermission(
1190 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1191 }
1192
Jake Hambye994d462014-02-03 13:10:13 -08001193 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001194 if (DBG_LOC) log("getCellLocation: is active user");
1195 Bundle data = new Bundle();
1196 mPhone.getCellLocation().fillInNotifierBundle(data);
1197 return data;
1198 } else {
1199 if (DBG_LOC) log("getCellLocation: suppress non-active user");
1200 return null;
1201 }
1202 }
1203
1204 @Override
1205 public void enableLocationUpdates() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001206 enableLocationUpdatesForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001207 }
1208
Wink Savilleb564aae2014-10-23 10:18:09 -07001209 public void enableLocationUpdatesForSubscriber(int subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001210 mApp.enforceCallingOrSelfPermission(
1211 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001212 getPhone(subId).enableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001213 }
1214
1215 @Override
1216 public void disableLocationUpdates() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001217 disableLocationUpdatesForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001218 }
1219
Wink Savilleb564aae2014-10-23 10:18:09 -07001220 public void disableLocationUpdatesForSubscriber(int subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001221 mApp.enforceCallingOrSelfPermission(
1222 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001223 getPhone(subId).disableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001224 }
1225
1226 @Override
1227 @SuppressWarnings("unchecked")
1228 public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1229 try {
1230 mApp.enforceCallingOrSelfPermission(
1231 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1232 } catch (SecurityException e) {
1233 // If we have ACCESS_FINE_LOCATION permission, skip the check
1234 // for ACCESS_COARSE_LOCATION
1235 // A failure should throw the SecurityException from
1236 // ACCESS_COARSE_LOCATION since this is the weaker precondition
1237 mApp.enforceCallingOrSelfPermission(
1238 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1239 }
1240
1241 if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1242 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1243 return null;
1244 }
Jake Hambye994d462014-02-03 13:10:13 -08001245 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001246 if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1247
1248 ArrayList<NeighboringCellInfo> cells = null;
1249
1250 try {
1251 cells = (ArrayList<NeighboringCellInfo>) sendRequest(
Wink Saville36469e72014-06-11 15:17:00 -07001252 CMD_HANDLE_NEIGHBORING_CELL, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001253 } catch (RuntimeException e) {
Wink Saville36469e72014-06-11 15:17:00 -07001254 Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001255 }
1256 return cells;
1257 } else {
1258 if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1259 return null;
1260 }
1261 }
1262
1263
1264 @Override
1265 public List<CellInfo> getAllCellInfo() {
1266 try {
1267 mApp.enforceCallingOrSelfPermission(
1268 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1269 } catch (SecurityException e) {
1270 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1271 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1272 // is the weaker precondition
1273 mApp.enforceCallingOrSelfPermission(
1274 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1275 }
1276
Jake Hambye994d462014-02-03 13:10:13 -08001277 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001278 if (DBG_LOC) log("getAllCellInfo: is active user");
1279 return mPhone.getAllCellInfo();
1280 } else {
1281 if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1282 return null;
1283 }
1284 }
1285
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -07001286 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001287 public void setCellInfoListRate(int rateInMillis) {
1288 mPhone.setCellInfoListRate(rateInMillis);
1289 }
1290
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001291 //
1292 // Internal helper methods.
1293 //
1294
Jake Hambye994d462014-02-03 13:10:13 -08001295 private static boolean checkIfCallerIsSelfOrForegroundUser() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001296 boolean ok;
1297
1298 boolean self = Binder.getCallingUid() == Process.myUid();
1299 if (!self) {
1300 // Get the caller's user id then clear the calling identity
1301 // which will be restored in the finally clause.
1302 int callingUser = UserHandle.getCallingUserId();
1303 long ident = Binder.clearCallingIdentity();
1304
1305 try {
1306 // With calling identity cleared the current user is the foreground user.
1307 int foregroundUser = ActivityManager.getCurrentUser();
1308 ok = (foregroundUser == callingUser);
1309 if (DBG_LOC) {
1310 log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1311 + " callingUser=" + callingUser + " ok=" + ok);
1312 }
1313 } catch (Exception ex) {
1314 if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1315 ok = false;
1316 } finally {
1317 Binder.restoreCallingIdentity(ident);
1318 }
1319 } else {
1320 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1321 ok = true;
1322 }
1323 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1324 return ok;
1325 }
1326
1327 /**
1328 * Make sure the caller has the READ_PHONE_STATE permission.
1329 *
1330 * @throws SecurityException if the caller does not have the required permission
1331 */
1332 private void enforceReadPermission() {
1333 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
1334 }
1335
1336 /**
1337 * Make sure the caller has the MODIFY_PHONE_STATE permission.
1338 *
1339 * @throws SecurityException if the caller does not have the required permission
1340 */
1341 private void enforceModifyPermission() {
1342 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1343 }
1344
1345 /**
Junda Liua2e36012014-07-09 18:30:01 -07001346 * Make sure either system app or the caller has carrier privilege.
1347 *
1348 * @throws SecurityException if the caller does not have the required permission/privilege
1349 */
1350 private void enforceModifyPermissionOrCarrierPrivilege() {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001351 int permission = mApp.checkCallingOrSelfPermission(
1352 android.Manifest.permission.MODIFY_PHONE_STATE);
1353 if (permission == PackageManager.PERMISSION_GRANTED) {
1354 return;
1355 }
1356
1357 log("No modify permission, check carrier privilege next.");
Shishir Agrawal5e5becd2014-11-18 11:38:23 -08001358 if (getCarrierPrivilegeStatus() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001359 loge("No Carrier Privilege.");
1360 throw new SecurityException("No modify permission or carrier privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001361 }
1362 }
1363
1364 /**
1365 * Make sure the caller has carrier privilege.
1366 *
1367 * @throws SecurityException if the caller does not have the required permission
1368 */
1369 private void enforceCarrierPrivilege() {
Shishir Agrawal5e5becd2014-11-18 11:38:23 -08001370 if (getCarrierPrivilegeStatus() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001371 loge("No Carrier Privilege.");
1372 throw new SecurityException("No Carrier Privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001373 }
1374 }
1375
1376 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001377 * Make sure the caller has the CALL_PHONE permission.
1378 *
1379 * @throws SecurityException if the caller does not have the required permission
1380 */
1381 private void enforceCallPermission() {
1382 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1383 }
1384
Shishir Agrawal566b7612013-10-28 14:41:00 -07001385 /**
Gabriel Peal36ebb0d2014-03-20 09:20:43 -07001386 * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1387 *
1388 * @throws SecurityException if the caller does not have the required permission
1389 */
1390 private void enforcePrivilegedPhoneStatePermission() {
1391 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1392 null);
1393 }
1394
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001395 private String createTelUrl(String number) {
1396 if (TextUtils.isEmpty(number)) {
1397 return null;
1398 }
1399
Jake Hambye994d462014-02-03 13:10:13 -08001400 return "tel:" + number;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001401 }
1402
Ihab Awadf9e92732013-12-05 18:02:52 -08001403 private static void log(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001404 Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1405 }
1406
Naveen Kalla1fd79bd2014-08-08 00:48:59 -07001407 private static void logv(String msg) {
1408 Log.v(LOG_TAG, "[PhoneIntfMgr] " + msg);
1409 }
1410
Ihab Awadf9e92732013-12-05 18:02:52 -08001411 private static void loge(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001412 Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1413 }
1414
1415 public int getActivePhoneType() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001416 return getActivePhoneTypeForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001417 }
1418
Wink Savilleb564aae2014-10-23 10:18:09 -07001419 public int getActivePhoneTypeForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001420 return getPhone(subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001421 }
1422
1423 /**
1424 * Returns the CDMA ERI icon index to display
1425 */
1426 public int getCdmaEriIconIndex() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001427 return getCdmaEriIconIndexForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001428
1429 }
1430
Wink Savilleb564aae2014-10-23 10:18:09 -07001431 public int getCdmaEriIconIndexForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001432 return getPhone(subId).getCdmaEriIconIndex();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001433 }
1434
1435 /**
1436 * Returns the CDMA ERI icon mode,
1437 * 0 - ON
1438 * 1 - FLASHING
1439 */
1440 public int getCdmaEriIconMode() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001441 return getCdmaEriIconModeForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001442 }
1443
Wink Savilleb564aae2014-10-23 10:18:09 -07001444 public int getCdmaEriIconModeForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001445 return getPhone(subId).getCdmaEriIconMode();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001446 }
1447
1448 /**
1449 * Returns the CDMA ERI text,
1450 */
1451 public String getCdmaEriText() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001452 return getCdmaEriTextForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001453 }
1454
Wink Savilleb564aae2014-10-23 10:18:09 -07001455 public String getCdmaEriTextForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001456 return getPhone(subId).getCdmaEriText();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001457 }
1458
1459 /**
Junda Liuca05d5d2014-08-14 22:36:34 -07001460 * Returns the CDMA MDN.
1461 */
Wink Savilleb564aae2014-10-23 10:18:09 -07001462 public String getCdmaMdn(int subId) {
Junda Liuca05d5d2014-08-14 22:36:34 -07001463 enforceModifyPermissionOrCarrierPrivilege();
1464 if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
1465 return getPhone(subId).getLine1Number();
1466 } else {
1467 return null;
1468 }
1469 }
1470
1471 /**
1472 * Returns the CDMA MIN.
1473 */
Wink Savilleb564aae2014-10-23 10:18:09 -07001474 public String getCdmaMin(int subId) {
Junda Liuca05d5d2014-08-14 22:36:34 -07001475 enforceModifyPermissionOrCarrierPrivilege();
1476 if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
1477 return getPhone(subId).getCdmaMin();
1478 } else {
1479 return null;
1480 }
1481 }
1482
1483 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001484 * Returns true if CDMA provisioning needs to run.
1485 */
1486 public boolean needsOtaServiceProvisioning() {
1487 return mPhone.needsOtaServiceProvisioning();
1488 }
1489
1490 /**
Shishir Agrawal76d5da92014-11-09 16:17:25 -08001491 * Sets the voice mail number of a given subId.
1492 */
1493 @Override
1494 public boolean setVoiceMailNumber(int subId, String alphaTag, String number) {
Shishir Agrawal5e5becd2014-11-18 11:38:23 -08001495 enforceCarrierPrivilege();
Shishir Agrawal76d5da92014-11-09 16:17:25 -08001496 Boolean success = (Boolean) sendRequest(CMD_SET_VOICEMAIL_NUMBER,
1497 new Pair<String, String>(alphaTag, number), new Integer(subId));
1498 return success;
1499 }
1500
1501 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001502 * Returns the unread count of voicemails
1503 */
1504 public int getVoiceMessageCount() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001505 return getVoiceMessageCountForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001506 }
1507
1508 /**
1509 * Returns the unread count of voicemails for a subId
1510 */
Wink Savilleb564aae2014-10-23 10:18:09 -07001511 public int getVoiceMessageCountForSubscriber( int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001512 return getPhone(subId).getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001513 }
1514
1515 /**
1516 * Returns the data network type
1517 *
1518 * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1519 */
1520 @Override
1521 public int getNetworkType() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001522 return getNetworkTypeForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001523 }
1524
1525 /**
1526 * Returns the network type for a subId
1527 */
1528 @Override
Wink Savilleb564aae2014-10-23 10:18:09 -07001529 public int getNetworkTypeForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001530 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001531 }
1532
1533 /**
1534 * Returns the data network type
1535 */
1536 @Override
1537 public int getDataNetworkType() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001538 return getDataNetworkTypeForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001539 }
1540
1541 /**
1542 * Returns the data network type for a subId
1543 */
1544 @Override
Wink Savilleb564aae2014-10-23 10:18:09 -07001545 public int getDataNetworkTypeForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001546 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001547 }
1548
1549 /**
1550 * Returns the data network type
1551 */
1552 @Override
1553 public int getVoiceNetworkType() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001554 return getVoiceNetworkTypeForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001555 }
1556
1557 /**
1558 * Returns the Voice network type for a subId
1559 */
1560 @Override
Wink Savilleb564aae2014-10-23 10:18:09 -07001561 public int getVoiceNetworkTypeForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001562 return getPhone(subId).getServiceState().getVoiceNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001563 }
1564
1565 /**
1566 * @return true if a ICC card is present
1567 */
1568 public boolean hasIccCard() {
Wink Saville36469e72014-06-11 15:17:00 -07001569 // FIXME Make changes to pass defaultSimId of type int
1570 return hasIccCardUsingSlotId(getDefaultSubscription());
1571 }
1572
1573 /**
1574 * @return true if a ICC card is present for a slotId
1575 */
Wink Savilleb564aae2014-10-23 10:18:09 -07001576 public boolean hasIccCardUsingSlotId(int slotId) {
Wink Saville36469e72014-06-11 15:17:00 -07001577 return getPhone(slotId).getIccCard().hasIccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001578 }
1579
1580 /**
1581 * Return if the current radio is LTE on CDMA. This
1582 * is a tri-state return value as for a period of time
1583 * the mode may be unknown.
1584 *
1585 * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
Jake Hambye994d462014-02-03 13:10:13 -08001586 * or {@link Phone#LTE_ON_CDMA_TRUE}
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001587 */
1588 public int getLteOnCdmaMode() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001589 return getLteOnCdmaModeForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001590 }
1591
Wink Savilleb564aae2014-10-23 10:18:09 -07001592 public int getLteOnCdmaModeForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001593 return getPhone(subId).getLteOnCdmaMode();
1594 }
1595
1596 public void setPhone(Phone phone) {
1597 mPhone = phone;
1598 }
1599
1600 /**
1601 * {@hide}
1602 * Returns Default subId, 0 in the case of single standby.
1603 */
Wink Savilleb564aae2014-10-23 10:18:09 -07001604 private int getDefaultSubscription() {
Wink Savilleac1bdfd2014-11-20 23:04:44 -08001605 return mSubscriptionController.getDefaultSubId();
Wink Saville36469e72014-06-11 15:17:00 -07001606 }
1607
Wink Savilleb564aae2014-10-23 10:18:09 -07001608 private int getPreferredVoiceSubscription() {
Wink Savilleac1bdfd2014-11-20 23:04:44 -08001609 return mSubscriptionController.getDefaultVoiceSubId();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001610 }
Ihab Awadf2177b72013-11-25 13:33:23 -08001611
1612 /**
1613 * @see android.telephony.TelephonyManager.WifiCallingChoices
1614 */
1615 public int getWhenToMakeWifiCalls() {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001616 return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1617 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
Ihab Awadf2177b72013-11-25 13:33:23 -08001618 }
1619
1620 /**
1621 * @see android.telephony.TelephonyManager.WifiCallingChoices
1622 */
1623 public void setWhenToMakeWifiCalls(int preference) {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001624 if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1625 Settings.System.putInt(mPhone.getContext().getContentResolver(),
1626 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
Ihab Awadf9e92732013-12-05 18:02:52 -08001627 }
1628
Sailesh Nepald1e68152013-12-12 19:08:02 -08001629 private static int getWhenToMakeWifiCallsDefaultPreference() {
Santos Cordonda120f42014-08-06 04:44:34 -07001630 // TODO: Use a build property to choose this value.
Evan Charlton9829e882013-12-19 15:30:38 -08001631 return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
Ihab Awadf2177b72013-11-25 13:33:23 -08001632 }
Shishir Agrawal69f68122013-12-16 17:25:49 -08001633
Shishir Agrawal566b7612013-10-28 14:41:00 -07001634 @Override
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001635 public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID) {
Junda Liua2e36012014-07-09 18:30:01 -07001636 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001637
1638 if (DBG) log("iccOpenLogicalChannel: " + AID);
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001639 IccOpenLogicalChannelResponse response = (IccOpenLogicalChannelResponse)sendRequest(
1640 CMD_OPEN_CHANNEL, AID);
1641 if (DBG) log("iccOpenLogicalChannel: " + response);
1642 return response;
Shishir Agrawal566b7612013-10-28 14:41:00 -07001643 }
1644
1645 @Override
1646 public boolean iccCloseLogicalChannel(int channel) {
Junda Liua2e36012014-07-09 18:30:01 -07001647 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001648
1649 if (DBG) log("iccCloseLogicalChannel: " + channel);
1650 if (channel < 0) {
1651 return false;
1652 }
Jake Hambye994d462014-02-03 13:10:13 -08001653 Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
Shishir Agrawal566b7612013-10-28 14:41:00 -07001654 if (DBG) log("iccCloseLogicalChannel: " + success);
1655 return success;
1656 }
1657
1658 @Override
1659 public String iccTransmitApduLogicalChannel(int channel, int cla,
1660 int command, int p1, int p2, int p3, String data) {
Junda Liua2e36012014-07-09 18:30:01 -07001661 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001662
1663 if (DBG) {
1664 log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1665 " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1666 " data=" + data);
1667 }
1668
1669 if (channel < 0) {
1670 return "";
1671 }
1672
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001673 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_LOGICAL_CHANNEL,
Shishir Agrawal566b7612013-10-28 14:41:00 -07001674 new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1675 if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1676
Shishir Agrawal566b7612013-10-28 14:41:00 -07001677 // Append the returned status code to the end of the response payload.
1678 String s = Integer.toHexString(
1679 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
Shishir Agrawal5ec14172014-08-05 17:05:45 -07001680 if (response.payload != null) {
1681 s = IccUtils.bytesToHexString(response.payload) + s;
1682 }
Shishir Agrawal566b7612013-10-28 14:41:00 -07001683 return s;
1684 }
Jake Hambye994d462014-02-03 13:10:13 -08001685
Evan Charltonc66da362014-05-16 14:06:40 -07001686 @Override
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001687 public String iccTransmitApduBasicChannel(int cla, int command, int p1, int p2,
1688 int p3, String data) {
1689 enforceModifyPermissionOrCarrierPrivilege();
1690
1691 if (DBG) {
1692 log("iccTransmitApduBasicChannel: cla=" + cla + " cmd=" + command + " p1="
1693 + p1 + " p2=" + p2 + " p3=" + p3 + " data=" + data);
1694 }
1695
1696 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_BASIC_CHANNEL,
1697 new IccAPDUArgument(0, cla, command, p1, p2, p3, data));
1698 if (DBG) log("iccTransmitApduBasicChannel: " + response);
1699
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001700 // Append the returned status code to the end of the response payload.
1701 String s = Integer.toHexString(
1702 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
Shishir Agrawal5ec14172014-08-05 17:05:45 -07001703 if (response.payload != null) {
1704 s = IccUtils.bytesToHexString(response.payload) + s;
1705 }
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001706 return s;
1707 }
1708
1709 @Override
1710 public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
1711 String filePath) {
1712 enforceModifyPermissionOrCarrierPrivilege();
1713
1714 if (DBG) {
1715 log("Exchange SIM_IO " + fileID + ":" + command + " " +
1716 p1 + " " + p2 + " " + p3 + ":" + filePath);
1717 }
1718
1719 IccIoResult response =
1720 (IccIoResult)sendRequest(CMD_EXCHANGE_SIM_IO,
Yong Jiang3edf3782014-10-03 13:23:28 -05001721 new IccAPDUArgument(-1, fileID, command, p1, p2, p3, filePath));
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001722
1723 if (DBG) {
1724 log("Exchange SIM_IO [R]" + response);
1725 }
1726
1727 byte[] result = null;
1728 int length = 2;
1729 if (response.payload != null) {
1730 length = 2 + response.payload.length;
1731 result = new byte[length];
1732 System.arraycopy(response.payload, 0, result, 0, response.payload.length);
1733 } else {
1734 result = new byte[length];
1735 }
1736
1737 result[length - 1] = (byte) response.sw2;
1738 result[length - 2] = (byte) response.sw1;
1739 return result;
1740 }
1741
1742 @Override
Evan Charltonc66da362014-05-16 14:06:40 -07001743 public String sendEnvelopeWithStatus(String content) {
Junda Liua2e36012014-07-09 18:30:01 -07001744 enforceModifyPermissionOrCarrierPrivilege();
Evan Charltonc66da362014-05-16 14:06:40 -07001745
1746 IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
1747 if (response.payload == null) {
1748 return "";
1749 }
1750
1751 // Append the returned status code to the end of the response payload.
1752 String s = Integer.toHexString(
1753 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1754 s = IccUtils.bytesToHexString(response.payload) + s;
1755 return s;
1756 }
1757
Jake Hambye994d462014-02-03 13:10:13 -08001758 /**
1759 * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1760 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1761 *
1762 * @param itemID the ID of the item to read
1763 * @return the NV item as a String, or null on error.
1764 */
1765 @Override
1766 public String nvReadItem(int itemID) {
Junda Liua2e36012014-07-09 18:30:01 -07001767 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001768 if (DBG) log("nvReadItem: item " + itemID);
1769 String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
1770 if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
1771 return value;
1772 }
1773
1774 /**
1775 * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1776 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1777 *
1778 * @param itemID the ID of the item to read
1779 * @param itemValue the value to write, as a String
1780 * @return true on success; false on any failure
1781 */
1782 @Override
1783 public boolean nvWriteItem(int itemID, String itemValue) {
Junda Liua2e36012014-07-09 18:30:01 -07001784 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001785 if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
1786 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
1787 new Pair<Integer, String>(itemID, itemValue));
1788 if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
1789 return success;
1790 }
1791
1792 /**
1793 * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
1794 * Used for device configuration by some CDMA operators.
1795 *
1796 * @param preferredRoamingList byte array containing the new PRL
1797 * @return true on success; false on any failure
1798 */
1799 @Override
1800 public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
Junda Liua2e36012014-07-09 18:30:01 -07001801 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001802 if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
1803 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
1804 if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
1805 return success;
1806 }
1807
1808 /**
1809 * Perform the specified type of NV config reset.
1810 * Used for device configuration by some CDMA operators.
1811 *
1812 * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
1813 * @return true on success; false on any failure
1814 */
1815 @Override
1816 public boolean nvResetConfig(int resetType) {
Junda Liua2e36012014-07-09 18:30:01 -07001817 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001818 if (DBG) log("nvResetConfig: type " + resetType);
1819 Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
1820 if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
1821 return success;
1822 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001823
1824 /**
Wink Saville36469e72014-06-11 15:17:00 -07001825 * {@hide}
1826 * Returns Default sim, 0 in the case of single standby.
1827 */
1828 public int getDefaultSim() {
1829 //TODO Need to get it from Telephony Devcontroller
1830 return 0;
1831 }
1832
ram87fca6f2014-07-18 18:58:44 +05301833 public String[] getPcscfAddress(String apnType) {
Wink Saville36469e72014-06-11 15:17:00 -07001834 enforceReadPermission();
ram87fca6f2014-07-18 18:58:44 +05301835 return mPhone.getPcscfAddress(apnType);
Wink Saville36469e72014-06-11 15:17:00 -07001836 }
1837
1838 public void setImsRegistrationState(boolean registered) {
1839 enforceModifyPermission();
1840 mPhone.setImsRegistrationState(registered);
1841 }
1842
1843 /**
Junda Liu84d15a22014-07-02 11:21:04 -07001844 * Get the calculated preferred network type.
1845 * Used for debugging incorrect network type.
1846 *
1847 * @return the preferred network type, defined in RILConstants.java.
1848 */
1849 @Override
1850 public int getCalculatedPreferredNetworkType() {
1851 enforceReadPermission();
Amit Mahajan43330e02014-11-18 11:54:45 -08001852 return PhoneFactory.calculatePreferredNetworkType(mPhone.getContext(), 0); // wink FIXME: need to get SubId from somewhere.
Junda Liu84d15a22014-07-02 11:21:04 -07001853 }
1854
1855 /**
Jake Hamby7c27be32014-03-03 13:25:59 -08001856 * Get the preferred network type.
1857 * Used for device configuration by some CDMA operators.
1858 *
1859 * @return the preferred network type, defined in RILConstants.java.
1860 */
1861 @Override
1862 public int getPreferredNetworkType() {
Junda Liua2e36012014-07-09 18:30:01 -07001863 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001864 if (DBG) log("getPreferredNetworkType");
1865 int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null);
1866 int networkType = (result != null ? result[0] : -1);
1867 if (DBG) log("getPreferredNetworkType: " + networkType);
1868 return networkType;
1869 }
1870
1871 /**
1872 * Set the preferred network type.
1873 * Used for device configuration by some CDMA operators.
1874 *
1875 * @param networkType the preferred network type, defined in RILConstants.java.
1876 * @return true on success; false on any failure.
1877 */
1878 @Override
1879 public boolean setPreferredNetworkType(int networkType) {
Junda Liua2e36012014-07-09 18:30:01 -07001880 enforceModifyPermissionOrCarrierPrivilege();
PauloftheWest3c6ce5e2014-11-03 07:09:47 -08001881 final int phoneSubId = mPhone.getSubId();
Jake Hamby7c27be32014-03-03 13:25:59 -08001882 if (DBG) log("setPreferredNetworkType: type " + networkType);
1883 Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType);
1884 if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
Junda Liu80bc0d12014-07-14 16:36:44 -07001885 if (success) {
1886 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
PauloftheWest3c6ce5e2014-11-03 07:09:47 -08001887 Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId, networkType);
Junda Liu80bc0d12014-07-14 16:36:44 -07001888 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001889 return success;
1890 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001891
1892 /**
Junda Liu475951f2014-11-07 16:45:03 -08001893 * Check TETHER_DUN_REQUIRED and TETHER_DUN_APN settings, net.tethering.noprovisioning
1894 * SystemProperty, and config_tether_apndata to decide whether DUN APN is required for
1895 * tethering.
1896 *
1897 * @return 0: Not required. 1: required. 2: Not set.
1898 * @hide
1899 */
1900 @Override
1901 public int getTetherApnRequired() {
1902 enforceModifyPermissionOrCarrierPrivilege();
1903 int dunRequired = Settings.Global.getInt(mPhone.getContext().getContentResolver(),
1904 Settings.Global.TETHER_DUN_REQUIRED, 2);
1905 // If not set, check net.tethering.noprovisioning, TETHER_DUN_APN setting and
1906 // config_tether_apndata.
1907 if (dunRequired == 2 && mPhone.hasMatchedTetherApnSetting()) {
1908 dunRequired = 1;
1909 }
1910 return dunRequired;
1911 }
1912
1913 /**
Robert Greenwalted86e582014-05-21 20:03:20 -07001914 * Set mobile data enabled
1915 * Used by the user through settings etc to turn on/off mobile data
1916 *
1917 * @param enable {@code true} turn turn data on, else {@code false}
1918 */
1919 @Override
Wink Savillee7353bb2014-12-05 14:21:41 -08001920 public void setDataEnabled(int subId, boolean enable) {
Robert Greenwalted86e582014-05-21 20:03:20 -07001921 enforceModifyPermission();
Wink Savillee7353bb2014-12-05 14:21:41 -08001922 int phoneId = mSubscriptionController.getPhoneId(subId);
1923 log("getDataEnabled: subId=" + subId + " phoneId=" + phoneId);
1924 Phone phone = PhoneFactory.getPhone(phoneId);
1925 if (phone != null) {
1926 log("setDataEnabled: subId=" + subId + " enable=" + enable);
1927 phone.setDataEnabled(enable);
1928 } else {
1929 loge("setDataEnabled: no phone for subId=" + subId);
1930 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001931 }
1932
1933 /**
Robert Greenwalt646120a2014-05-23 11:54:03 -07001934 * Get whether mobile data is enabled.
1935 *
1936 * Note that this used to be available from ConnectivityService, gated by
1937 * ACCESS_NETWORK_STATE permission, so this will accept either that or
1938 * our MODIFY_PHONE_STATE.
Robert Greenwalted86e582014-05-21 20:03:20 -07001939 *
1940 * @return {@code true} if data is enabled else {@code false}
1941 */
1942 @Override
Wink Savillee7353bb2014-12-05 14:21:41 -08001943 public boolean getDataEnabled(int subId) {
Robert Greenwalt646120a2014-05-23 11:54:03 -07001944 try {
1945 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
1946 null);
1947 } catch (Exception e) {
1948 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
1949 null);
1950 }
Wink Savillee7353bb2014-12-05 14:21:41 -08001951 int phoneId = mSubscriptionController.getPhoneId(subId);
1952 log("getDataEnabled: subId=" + subId + " phoneId=" + phoneId);
1953 Phone phone = PhoneFactory.getPhone(phoneId);
1954 if (phone != null) {
1955 boolean retVal = phone.getDataEnabled();
1956 log("getDataEnabled: subId=" + subId + " retVal=" + retVal);
1957 return retVal;
1958 } else {
1959 loge("getDataEnabled: no phone subId=" + subId + " retVal=false");
1960 return false;
1961 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001962 }
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001963
1964 @Override
Shishir Agrawal5e5becd2014-11-18 11:38:23 -08001965 public int getCarrierPrivilegeStatus() {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001966 UiccCard card = UiccController.getInstance().getUiccCard();
1967 if (card == null) {
Shishir Agrawal5e5becd2014-11-18 11:38:23 -08001968 loge("getCarrierPrivilegeStatus: No UICC");
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001969 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1970 }
1971 return card.getCarrierPrivilegeStatusForCurrentTransaction(
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001972 mPhone.getContext().getPackageManager());
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001973 }
Junda Liu29340342014-07-10 15:23:27 -07001974
1975 @Override
Shishir Agrawal6d5a2852014-07-11 16:32:57 -07001976 public int checkCarrierPrivilegesForPackage(String pkgname) {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001977 UiccCard card = UiccController.getInstance().getUiccCard();
1978 if (card == null) {
1979 loge("checkCarrierPrivilegesForPackage: No UICC");
1980 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1981 }
1982 return card.getCarrierPrivilegeStatus(mPhone.getContext().getPackageManager(), pkgname);
Junda Liu29340342014-07-10 15:23:27 -07001983 }
Derek Tan89e89d42014-07-08 17:00:10 -07001984
1985 @Override
Diego Pontorieroaf74c862014-08-28 11:51:16 -07001986 public List<String> getCarrierPackageNamesForIntent(Intent intent) {
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001987 UiccCard card = UiccController.getInstance().getUiccCard();
1988 if (card == null) {
Diego Pontorieroaf74c862014-08-28 11:51:16 -07001989 loge("getCarrierPackageNamesForIntent: No UICC");
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001990 return null ;
1991 }
Diego Pontorieroaf74c862014-08-28 11:51:16 -07001992 return card.getCarrierPackageNamesForIntent(
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001993 mPhone.getContext().getPackageManager(), intent);
1994 }
1995
Wink Savilleb564aae2014-10-23 10:18:09 -07001996 private String getIccId(int subId) {
Derek Tan97ebb422014-09-05 16:55:38 -07001997 UiccCard card = getPhone(subId).getUiccCard();
1998 if (card == null) {
1999 loge("getIccId: No UICC");
2000 return null;
2001 }
2002 String iccId = card.getIccId();
2003 if (TextUtils.isEmpty(iccId)) {
2004 loge("getIccId: ICC ID is null or empty.");
2005 return null;
2006 }
2007 return iccId;
2008 }
2009
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07002010 @Override
Jeff Sharkey85190e62014-12-05 09:40:12 -08002011 public boolean setLine1NumberForDisplayForSubscriber(int subId, String alphaTag,
2012 String number) {
Shishir Agrawal5e5becd2014-11-18 11:38:23 -08002013 enforceCarrierPrivilege();
Derek Tan97ebb422014-09-05 16:55:38 -07002014
Jeff Sharkey85190e62014-12-05 09:40:12 -08002015 final String iccId = getIccId(subId);
2016 final String subscriberId = getPhone(subId).getSubscriberId();
2017
2018 if (DBG_MERGE) {
2019 Slog.d(LOG_TAG, "Setting line number for ICC=" + iccId + ", subscriberId="
2020 + subscriberId + " to " + number);
2021 }
2022
Shishir Agrawal495d7e12014-12-01 11:50:28 -08002023 if (TextUtils.isEmpty(iccId)) {
2024 return false;
Derek Tan97ebb422014-09-05 16:55:38 -07002025 }
Shishir Agrawal495d7e12014-12-01 11:50:28 -08002026
Jeff Sharkey85190e62014-12-05 09:40:12 -08002027 final SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
2028
2029 final String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
Shishir Agrawal495d7e12014-12-01 11:50:28 -08002030 if (alphaTag == null) {
2031 editor.remove(alphaTagPrefKey);
2032 } else {
2033 editor.putString(alphaTagPrefKey, alphaTag);
2034 }
2035
Jeff Sharkey85190e62014-12-05 09:40:12 -08002036 // Record both the line number and IMSI for this ICCID, since we need to
2037 // track all merged IMSIs based on line number
2038 final String numberPrefKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
2039 final String subscriberPrefKey = PREF_CARRIERS_SUBSCRIBER_PREFIX + iccId;
Shishir Agrawal495d7e12014-12-01 11:50:28 -08002040 if (number == null) {
2041 editor.remove(numberPrefKey);
Jeff Sharkey85190e62014-12-05 09:40:12 -08002042 editor.remove(subscriberPrefKey);
Shishir Agrawal495d7e12014-12-01 11:50:28 -08002043 } else {
2044 editor.putString(numberPrefKey, number);
Jeff Sharkey85190e62014-12-05 09:40:12 -08002045 editor.putString(subscriberPrefKey, subscriberId);
Shishir Agrawal495d7e12014-12-01 11:50:28 -08002046 }
Jeff Sharkey85190e62014-12-05 09:40:12 -08002047
Shishir Agrawal495d7e12014-12-01 11:50:28 -08002048 editor.commit();
2049 return true;
Derek Tan7226c842014-07-02 17:42:23 -07002050 }
2051
2052 @Override
Wink Savilleb564aae2014-10-23 10:18:09 -07002053 public String getLine1NumberForDisplay(int subId) {
Derek Tan7226c842014-07-02 17:42:23 -07002054 enforceReadPermission();
Derek Tan97ebb422014-09-05 16:55:38 -07002055
2056 String iccId = getIccId(subId);
2057 if (iccId != null) {
2058 String numberPrefKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
Andrew Leedf14ead2014-10-17 14:22:52 -07002059 return mTelephonySharedPreferences.getString(numberPrefKey, null);
Derek Tan7226c842014-07-02 17:42:23 -07002060 }
Derek Tan97ebb422014-09-05 16:55:38 -07002061 return null;
Derek Tan7226c842014-07-02 17:42:23 -07002062 }
2063
2064 @Override
Wink Savilleb564aae2014-10-23 10:18:09 -07002065 public String getLine1AlphaTagForDisplay(int subId) {
Derek Tan7226c842014-07-02 17:42:23 -07002066 enforceReadPermission();
Derek Tan97ebb422014-09-05 16:55:38 -07002067
2068 String iccId = getIccId(subId);
2069 if (iccId != null) {
2070 String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
Andrew Leedf14ead2014-10-17 14:22:52 -07002071 return mTelephonySharedPreferences.getString(alphaTagPrefKey, null);
Derek Tan7226c842014-07-02 17:42:23 -07002072 }
Derek Tan97ebb422014-09-05 16:55:38 -07002073 return null;
Derek Tan7226c842014-07-02 17:42:23 -07002074 }
Shishir Agrawalb1ebf8c2014-07-17 16:32:41 -07002075
2076 @Override
Jeff Sharkey85190e62014-12-05 09:40:12 -08002077 public String[] getMergedSubscriberIds() {
2078 final Context context = mPhone.getContext();
2079 final TelephonyManager tele = TelephonyManager.from(context);
2080 final SubscriptionManager sub = SubscriptionManager.from(context);
2081
2082 // Figure out what subscribers are currently active
2083 final ArraySet<String> activeSubscriberIds = new ArraySet<>();
2084 final int[] subIds = sub.getActiveSubscriptionIdList();
2085 for (int subId : subIds) {
2086 activeSubscriberIds.add(tele.getSubscriberId(subId));
2087 }
2088
2089 // First pass, find a number override for an active subscriber
2090 String mergeNumber = null;
2091 final Map<String, ?> prefs = mTelephonySharedPreferences.getAll();
2092 for (String key : prefs.keySet()) {
2093 if (key.startsWith(PREF_CARRIERS_SUBSCRIBER_PREFIX)) {
2094 final String subscriberId = (String) prefs.get(key);
2095 if (activeSubscriberIds.contains(subscriberId)) {
2096 final String iccId = key.substring(PREF_CARRIERS_SUBSCRIBER_PREFIX.length());
2097 final String numberKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
2098 mergeNumber = (String) prefs.get(numberKey);
2099 if (DBG_MERGE) {
2100 Slog.d(LOG_TAG, "Found line number " + mergeNumber
2101 + " for active subscriber " + subscriberId);
2102 }
2103 if (!TextUtils.isEmpty(mergeNumber)) {
2104 break;
2105 }
2106 }
2107 }
2108 }
2109
2110 // Shortcut when no active merged subscribers
2111 if (TextUtils.isEmpty(mergeNumber)) {
2112 return null;
2113 }
2114
2115 // Second pass, find all subscribers under that line override
2116 final ArraySet<String> result = new ArraySet<>();
2117 for (String key : prefs.keySet()) {
2118 if (key.startsWith(PREF_CARRIERS_NUMBER_PREFIX)) {
2119 final String number = (String) prefs.get(key);
2120 if (mergeNumber.equals(number)) {
2121 final String iccId = key.substring(PREF_CARRIERS_NUMBER_PREFIX.length());
2122 final String subscriberKey = PREF_CARRIERS_SUBSCRIBER_PREFIX + iccId;
2123 final String subscriberId = (String) prefs.get(subscriberKey);
2124 if (!TextUtils.isEmpty(subscriberId)) {
2125 result.add(subscriberId);
2126 }
2127 }
2128 }
2129 }
2130
2131 final String[] resultArray = result.toArray(new String[result.size()]);
2132 Arrays.sort(resultArray);
2133 if (DBG_MERGE) {
2134 Slog.d(LOG_TAG, "Found subscribers " + Arrays.toString(resultArray) + " after merge");
2135 }
2136 return resultArray;
2137 }
2138
2139 @Override
Shishir Agrawala3dfd752014-09-04 13:25:42 -07002140 public boolean setOperatorBrandOverride(String brand) {
Shishir Agrawal5e5becd2014-11-18 11:38:23 -08002141 enforceCarrierPrivilege();
Shishir Agrawala3dfd752014-09-04 13:25:42 -07002142 return mPhone.setOperatorBrandOverride(brand);
Shishir Agrawalb1ebf8c2014-07-17 16:32:41 -07002143 }
Steven Liu4bf01bc2014-07-17 11:05:29 -05002144
2145 @Override
2146 public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
2147 enforceModifyPermission();
2148
2149 int returnValue = 0;
2150 try {
2151 AsyncResult result = (AsyncResult)sendRequest(CMD_INVOKE_OEM_RIL_REQUEST_RAW, oemReq);
2152 if(result.exception == null) {
2153 if (result.result != null) {
2154 byte[] responseData = (byte[])(result.result);
2155 if(responseData.length > oemResp.length) {
2156 Log.w(LOG_TAG, "Buffer to copy response too small: Response length is " +
2157 responseData.length + "bytes. Buffer Size is " +
2158 oemResp.length + "bytes.");
2159 }
2160 System.arraycopy(responseData, 0, oemResp, 0, responseData.length);
2161 returnValue = responseData.length;
2162 }
2163 } else {
2164 CommandException ex = (CommandException) result.exception;
2165 returnValue = ex.getCommandError().ordinal();
2166 if(returnValue > 0) returnValue *= -1;
2167 }
2168 } catch (RuntimeException e) {
2169 Log.w(LOG_TAG, "sendOemRilRequestRaw: Runtime Exception");
2170 returnValue = (CommandException.Error.GENERIC_FAILURE.ordinal());
2171 if(returnValue > 0) returnValue *= -1;
2172 }
2173
2174 return returnValue;
2175 }
Wink Saville5d475dd2014-10-17 15:00:58 -07002176
2177 @Override
2178 public void setRadioCapability(RadioAccessFamily[] rafs) {
2179 try {
2180 ProxyController.getInstance().setRadioCapability(rafs);
2181 } catch (RuntimeException e) {
2182 Log.w(LOG_TAG, "setRadioCapability: Runtime Exception");
2183 }
2184 }
2185
2186 @Override
2187 public int getRadioAccessFamily(int phoneId) {
2188 return ProxyController.getInstance().getRadioAccessFamily(phoneId);
2189 }
Andrew Leedf14ead2014-10-17 14:22:52 -07002190
2191 @Override
2192 public void enableVideoCalling(boolean enable) {
2193 enforceModifyPermission();
2194 SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
2195 editor.putBoolean(PREF_ENABLE_VIDEO_CALLING, enable);
2196 editor.commit();
2197 }
2198
2199 @Override
2200 public boolean isVideoCallingEnabled() {
2201 enforceReadPermission();
Andrew Lee77527ac2014-10-21 16:57:39 -07002202 // Check the user preference and the system-level IMS setting. Even if the user has
2203 // enabled video calling, if IMS is disabled we aren't able to support video calling.
2204 // In the long run, we may instead need to check if there exists a connection service
2205 // which can support video calling.
Andrew Lee312e8172014-10-23 17:01:36 -07002206 return ImsManager.isVtEnabledByPlatform(mPhone.getContext())
2207 && ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mPhone.getContext())
2208 && mTelephonySharedPreferences.getBoolean(PREF_ENABLE_VIDEO_CALLING, true);
Andrew Leedf14ead2014-10-17 14:22:52 -07002209 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07002210}