blob: c71ea790cb8ef79bfe7cba98423888d1ec331989 [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;
Wink Saville36469e72014-06-11 15:17:00 -070024import android.net.ConnectivityManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070025import android.net.Uri;
26import android.os.AsyncResult;
27import android.os.Binder;
28import android.os.Bundle;
29import android.os.Handler;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070030import android.os.IBinder;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070031import android.os.Looper;
32import android.os.Message;
33import android.os.Process;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070034import android.os.RemoteException;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070035import android.os.ServiceManager;
36import android.os.UserHandle;
Ihab Awadf2177b72013-11-25 13:33:23 -080037import android.provider.Settings;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070038import android.telephony.CellInfo;
Jake Hambye994d462014-02-03 13:10:13 -080039import android.telephony.NeighboringCellInfo;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070040import android.telephony.ServiceState;
Wink Saville36469e72014-06-11 15:17:00 -070041import android.telephony.SubscriptionManager;
Ihab Awadf2177b72013-11-25 13:33:23 -080042import android.telephony.TelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070043import android.text.TextUtils;
44import android.util.Log;
Jake Hambye994d462014-02-03 13:10:13 -080045import android.util.Pair;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070046
Shishir Agrawal566b7612013-10-28 14:41:00 -070047import com.android.internal.telephony.CallManager;
48import com.android.internal.telephony.CommandException;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070049import com.android.internal.telephony.Connection;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070050import com.android.internal.telephony.DefaultPhoneNotifier;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070051import com.android.internal.telephony.ITelephony;
Jake Hambye994d462014-02-03 13:10:13 -080052import com.android.internal.telephony.IccCard;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070053import com.android.internal.telephony.Phone;
Wink Saville36469e72014-06-11 15:17:00 -070054import com.android.internal.telephony.PhoneFactory;
55import com.android.internal.telephony.CallManager;
56import com.android.internal.telephony.CommandException;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070057import com.android.internal.telephony.PhoneConstants;
Wink Saville36469e72014-06-11 15:17:00 -070058import com.android.internal.telephony.dataconnection.DctController;
Shishir Agrawal566b7612013-10-28 14:41:00 -070059import com.android.internal.telephony.uicc.IccIoResult;
60import com.android.internal.telephony.uicc.IccUtils;
61import com.android.internal.telephony.uicc.UiccController;
Jake Hambye994d462014-02-03 13:10:13 -080062import com.android.internal.util.HexDump;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070063import com.android.services.telephony.common.Call;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070064
Wink Saville36469e72014-06-11 15:17:00 -070065import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
66
Santos Cordon7d4ddf62013-07-10 11:58:08 -070067import java.util.ArrayList;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070068import java.util.HashMap;
69import java.util.Iterator;
Jake Hambye994d462014-02-03 13:10:13 -080070import java.util.List;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070071import java.util.Map;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070072
73/**
74 * Implementation of the ITelephony interface.
75 */
Santos Cordon117fee72014-05-16 17:56:12 -070076public class PhoneInterfaceManager extends ITelephony.Stub {
Santos Cordon7d4ddf62013-07-10 11:58:08 -070077 private static final String LOG_TAG = "PhoneInterfaceManager";
78 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
79 private static final boolean DBG_LOC = false;
80
81 // Message codes used with mMainThreadHandler
82 private static final int CMD_HANDLE_PIN_MMI = 1;
83 private static final int CMD_HANDLE_NEIGHBORING_CELL = 2;
84 private static final int EVENT_NEIGHBORING_CELL_DONE = 3;
85 private static final int CMD_ANSWER_RINGING_CALL = 4;
86 private static final int CMD_END_CALL = 5; // not used yet
87 private static final int CMD_SILENCE_RINGER = 6;
Shishir Agrawal566b7612013-10-28 14:41:00 -070088 private static final int CMD_TRANSMIT_APDU = 7;
89 private static final int EVENT_TRANSMIT_APDU_DONE = 8;
90 private static final int CMD_OPEN_CHANNEL = 9;
91 private static final int EVENT_OPEN_CHANNEL_DONE = 10;
92 private static final int CMD_CLOSE_CHANNEL = 11;
93 private static final int EVENT_CLOSE_CHANNEL_DONE = 12;
Jake Hambye994d462014-02-03 13:10:13 -080094 private static final int CMD_NV_READ_ITEM = 13;
95 private static final int EVENT_NV_READ_ITEM_DONE = 14;
96 private static final int CMD_NV_WRITE_ITEM = 15;
97 private static final int EVENT_NV_WRITE_ITEM_DONE = 16;
98 private static final int CMD_NV_WRITE_CDMA_PRL = 17;
99 private static final int EVENT_NV_WRITE_CDMA_PRL_DONE = 18;
100 private static final int CMD_NV_RESET_CONFIG = 19;
101 private static final int EVENT_NV_RESET_CONFIG_DONE = 20;
Jake Hamby7c27be32014-03-03 13:25:59 -0800102 private static final int CMD_GET_PREFERRED_NETWORK_TYPE = 21;
103 private static final int EVENT_GET_PREFERRED_NETWORK_TYPE_DONE = 22;
104 private static final int CMD_SET_PREFERRED_NETWORK_TYPE = 23;
105 private static final int EVENT_SET_PREFERRED_NETWORK_TYPE_DONE = 24;
Sailesh Nepal35b59452014-03-06 09:26:56 -0800106 private static final int CMD_SEND_ENVELOPE = 25;
107 private static final int EVENT_SEND_ENVELOPE_DONE = 26;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700108
109 /** The singleton instance. */
110 private static PhoneInterfaceManager sInstance;
111
112 PhoneGlobals mApp;
113 Phone mPhone;
114 CallManager mCM;
115 AppOpsManager mAppOps;
116 MainThreadHandler mMainThreadHandler;
Santos Cordon406c0342013-08-28 00:07:47 -0700117 CallHandlerServiceProxy mCallHandlerService;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700118
119 /**
Shishir Agrawal566b7612013-10-28 14:41:00 -0700120 * A request object to use for transmitting data to an ICC.
121 */
122 private static final class IccAPDUArgument {
123 public int channel, cla, command, p1, p2, p3;
124 public String data;
125
126 public IccAPDUArgument(int channel, int cla, int command,
127 int p1, int p2, int p3, String data) {
128 this.channel = channel;
129 this.cla = cla;
130 this.command = command;
131 this.p1 = p1;
132 this.p2 = p2;
133 this.p3 = p3;
134 this.data = data;
135 }
136 }
137
138 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700139 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
140 * request after sending. The main thread will notify the request when it is complete.
141 */
142 private static final class MainThreadRequest {
143 /** The argument to use for the request */
144 public Object argument;
145 /** The result of the request that is run on the main thread */
146 public Object result;
147
148 public MainThreadRequest(Object argument) {
149 this.argument = argument;
150 }
151 }
152
Sailesh Nepalcc0375f2013-11-13 09:15:18 -0800153 private static final class IncomingThirdPartyCallArgs {
154 public final ComponentName component;
155 public final String callId;
156 public final String callerDisplayName;
157
158 public IncomingThirdPartyCallArgs(ComponentName component, String callId,
159 String callerDisplayName) {
160 this.component = component;
161 this.callId = callId;
162 this.callerDisplayName = callerDisplayName;
163 }
164 }
165
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700166 /**
167 * A handler that processes messages on the main thread in the phone process. Since many
168 * of the Phone calls are not thread safe this is needed to shuttle the requests from the
169 * inbound binder threads to the main thread in the phone process. The Binder thread
170 * may provide a {@link MainThreadRequest} object in the msg.obj field that they are waiting
171 * on, which will be notified when the operation completes and will contain the result of the
172 * request.
173 *
174 * <p>If a MainThreadRequest object is provided in the msg.obj field,
175 * note that request.result must be set to something non-null for the calling thread to
176 * unblock.
177 */
178 private final class MainThreadHandler extends Handler {
179 @Override
180 public void handleMessage(Message msg) {
181 MainThreadRequest request;
182 Message onCompleted;
183 AsyncResult ar;
184
185 switch (msg.what) {
186 case CMD_HANDLE_PIN_MMI:
187 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800188 request.result = mPhone.handlePinMmi((String) request.argument);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700189 // Wake up the requesting thread
190 synchronized (request) {
191 request.notifyAll();
192 }
193 break;
194
195 case CMD_HANDLE_NEIGHBORING_CELL:
196 request = (MainThreadRequest) msg.obj;
197 onCompleted = obtainMessage(EVENT_NEIGHBORING_CELL_DONE,
198 request);
199 mPhone.getNeighboringCids(onCompleted);
200 break;
201
202 case EVENT_NEIGHBORING_CELL_DONE:
203 ar = (AsyncResult) msg.obj;
204 request = (MainThreadRequest) ar.userObj;
205 if (ar.exception == null && ar.result != null) {
206 request.result = ar.result;
207 } else {
208 // create an empty list to notify the waiting thread
Jake Hambye994d462014-02-03 13:10:13 -0800209 request.result = new ArrayList<NeighboringCellInfo>(0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700210 }
211 // Wake up the requesting thread
212 synchronized (request) {
213 request.notifyAll();
214 }
215 break;
216
217 case CMD_ANSWER_RINGING_CALL:
218 answerRingingCallInternal();
219 break;
220
221 case CMD_SILENCE_RINGER:
222 silenceRingerInternal();
223 break;
224
225 case CMD_END_CALL:
226 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800227 boolean hungUp;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700228 int phoneType = mPhone.getPhoneType();
229 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
230 // CDMA: If the user presses the Power button we treat it as
231 // ending the complete call session
232 hungUp = PhoneUtils.hangupRingingAndActive(mPhone);
233 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
234 // GSM: End the call as per the Phone state
235 hungUp = PhoneUtils.hangup(mCM);
236 } else {
237 throw new IllegalStateException("Unexpected phone type: " + phoneType);
238 }
239 if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up"));
240 request.result = hungUp;
241 // Wake up the requesting thread
242 synchronized (request) {
243 request.notifyAll();
244 }
245 break;
246
Shishir Agrawal566b7612013-10-28 14:41:00 -0700247 case CMD_TRANSMIT_APDU:
248 request = (MainThreadRequest) msg.obj;
249 IccAPDUArgument argument = (IccAPDUArgument) request.argument;
250 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_DONE, request);
251 UiccController.getInstance().getUiccCard().iccTransmitApduLogicalChannel(
252 argument.channel, argument.cla, argument.command,
253 argument.p1, argument.p2, argument.p3, argument.data,
254 onCompleted);
255 break;
256
257 case EVENT_TRANSMIT_APDU_DONE:
258 ar = (AsyncResult) msg.obj;
259 request = (MainThreadRequest) ar.userObj;
260 if (ar.exception == null && ar.result != null) {
261 request.result = ar.result;
262 } else {
263 request.result = new IccIoResult(0x6F, 0, (byte[])null);
264 if (ar.result == null) {
265 loge("iccTransmitApduLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800266 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700267 loge("iccTransmitApduLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800268 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700269 } else {
270 loge("iccTransmitApduLogicalChannel: Unknown exception");
271 }
272 }
273 synchronized (request) {
274 request.notifyAll();
275 }
276 break;
277
Derek Tan4d5e5c12014-02-04 11:54:58 -0800278 case CMD_SEND_ENVELOPE:
279 request = (MainThreadRequest) msg.obj;
280 onCompleted = obtainMessage(EVENT_SEND_ENVELOPE_DONE, request);
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700281 UiccController.getInstance().getUiccCard().sendEnvelopeWithStatus(
Derek Tan4d5e5c12014-02-04 11:54:58 -0800282 (String)request.argument, onCompleted);
283 break;
284
285 case EVENT_SEND_ENVELOPE_DONE:
286 ar = (AsyncResult) msg.obj;
287 request = (MainThreadRequest) ar.userObj;
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700288 if (ar.exception == null && ar.result != null) {
289 request.result = ar.result;
Derek Tan4d5e5c12014-02-04 11:54:58 -0800290 } else {
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700291 request.result = new IccIoResult(0x6F, 0, (byte[])null);
292 if (ar.result == null) {
293 loge("sendEnvelopeWithStatus: Empty response");
294 } else if (ar.exception instanceof CommandException) {
295 loge("sendEnvelopeWithStatus: CommandException: " +
296 ar.exception);
297 } else {
298 loge("sendEnvelopeWithStatus: exception:" + ar.exception);
299 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800300 }
301 synchronized (request) {
302 request.notifyAll();
303 }
304 break;
305
Shishir Agrawal566b7612013-10-28 14:41:00 -0700306 case CMD_OPEN_CHANNEL:
307 request = (MainThreadRequest) msg.obj;
308 onCompleted = obtainMessage(EVENT_OPEN_CHANNEL_DONE, request);
309 UiccController.getInstance().getUiccCard().iccOpenLogicalChannel(
310 (String)request.argument, onCompleted);
311 break;
312
313 case EVENT_OPEN_CHANNEL_DONE:
314 ar = (AsyncResult) msg.obj;
315 request = (MainThreadRequest) ar.userObj;
316 if (ar.exception == null && ar.result != null) {
Jake Hambye994d462014-02-03 13:10:13 -0800317 request.result = ((int[]) ar.result)[0];
Shishir Agrawal566b7612013-10-28 14:41:00 -0700318 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800319 request.result = -1;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700320 if (ar.result == null) {
321 loge("iccOpenLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800322 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700323 loge("iccOpenLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800324 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700325 } else {
326 loge("iccOpenLogicalChannel: Unknown exception");
327 }
328 }
329 synchronized (request) {
330 request.notifyAll();
331 }
332 break;
333
334 case CMD_CLOSE_CHANNEL:
335 request = (MainThreadRequest) msg.obj;
336 onCompleted = obtainMessage(EVENT_CLOSE_CHANNEL_DONE,
337 request);
338 UiccController.getInstance().getUiccCard().iccCloseLogicalChannel(
Jake Hambye994d462014-02-03 13:10:13 -0800339 (Integer) request.argument,
Shishir Agrawal566b7612013-10-28 14:41:00 -0700340 onCompleted);
341 break;
342
343 case EVENT_CLOSE_CHANNEL_DONE:
Jake Hambye994d462014-02-03 13:10:13 -0800344 handleNullReturnEvent(msg, "iccCloseLogicalChannel");
345 break;
346
347 case CMD_NV_READ_ITEM:
348 request = (MainThreadRequest) msg.obj;
349 onCompleted = obtainMessage(EVENT_NV_READ_ITEM_DONE, request);
350 mPhone.nvReadItem((Integer) request.argument, onCompleted);
351 break;
352
353 case EVENT_NV_READ_ITEM_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700354 ar = (AsyncResult) msg.obj;
355 request = (MainThreadRequest) ar.userObj;
Jake Hambye994d462014-02-03 13:10:13 -0800356 if (ar.exception == null && ar.result != null) {
357 request.result = ar.result; // String
Shishir Agrawal566b7612013-10-28 14:41:00 -0700358 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800359 request.result = "";
360 if (ar.result == null) {
361 loge("nvReadItem: Empty response");
362 } else if (ar.exception instanceof CommandException) {
363 loge("nvReadItem: CommandException: " +
364 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700365 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800366 loge("nvReadItem: Unknown exception");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700367 }
368 }
369 synchronized (request) {
370 request.notifyAll();
371 }
372 break;
373
Jake Hambye994d462014-02-03 13:10:13 -0800374 case CMD_NV_WRITE_ITEM:
375 request = (MainThreadRequest) msg.obj;
376 onCompleted = obtainMessage(EVENT_NV_WRITE_ITEM_DONE, request);
377 Pair<Integer, String> idValue = (Pair<Integer, String>) request.argument;
378 mPhone.nvWriteItem(idValue.first, idValue.second, onCompleted);
379 break;
380
381 case EVENT_NV_WRITE_ITEM_DONE:
382 handleNullReturnEvent(msg, "nvWriteItem");
383 break;
384
385 case CMD_NV_WRITE_CDMA_PRL:
386 request = (MainThreadRequest) msg.obj;
387 onCompleted = obtainMessage(EVENT_NV_WRITE_CDMA_PRL_DONE, request);
388 mPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
389 break;
390
391 case EVENT_NV_WRITE_CDMA_PRL_DONE:
392 handleNullReturnEvent(msg, "nvWriteCdmaPrl");
393 break;
394
395 case CMD_NV_RESET_CONFIG:
396 request = (MainThreadRequest) msg.obj;
397 onCompleted = obtainMessage(EVENT_NV_RESET_CONFIG_DONE, request);
398 mPhone.nvResetConfig((Integer) request.argument, onCompleted);
399 break;
400
401 case EVENT_NV_RESET_CONFIG_DONE:
402 handleNullReturnEvent(msg, "nvResetConfig");
403 break;
404
Jake Hamby7c27be32014-03-03 13:25:59 -0800405 case CMD_GET_PREFERRED_NETWORK_TYPE:
406 request = (MainThreadRequest) msg.obj;
407 onCompleted = obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE_DONE, request);
408 mPhone.getPreferredNetworkType(onCompleted);
409 break;
410
411 case EVENT_GET_PREFERRED_NETWORK_TYPE_DONE:
412 ar = (AsyncResult) msg.obj;
413 request = (MainThreadRequest) ar.userObj;
414 if (ar.exception == null && ar.result != null) {
415 request.result = ar.result; // Integer
416 } else {
417 request.result = -1;
418 if (ar.result == null) {
419 loge("getPreferredNetworkType: Empty response");
420 } else if (ar.exception instanceof CommandException) {
421 loge("getPreferredNetworkType: CommandException: " +
422 ar.exception);
423 } else {
424 loge("getPreferredNetworkType: Unknown exception");
425 }
426 }
427 synchronized (request) {
428 request.notifyAll();
429 }
430 break;
431
432 case CMD_SET_PREFERRED_NETWORK_TYPE:
433 request = (MainThreadRequest) msg.obj;
434 onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);
435 int networkType = (Integer) request.argument;
436 mPhone.setPreferredNetworkType(networkType, onCompleted);
437 break;
438
439 case EVENT_SET_PREFERRED_NETWORK_TYPE_DONE:
440 handleNullReturnEvent(msg, "setPreferredNetworkType");
441 break;
442
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700443 default:
444 Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
445 break;
446 }
447 }
Jake Hambye994d462014-02-03 13:10:13 -0800448
449 private void handleNullReturnEvent(Message msg, String command) {
450 AsyncResult ar = (AsyncResult) msg.obj;
451 MainThreadRequest request = (MainThreadRequest) ar.userObj;
452 if (ar.exception == null) {
453 request.result = true;
454 } else {
455 request.result = false;
456 if (ar.exception instanceof CommandException) {
457 loge(command + ": CommandException: " + ar.exception);
458 } else {
459 loge(command + ": Unknown exception");
460 }
461 }
462 synchronized (request) {
463 request.notifyAll();
464 }
465 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700466 }
467
468 /**
469 * Posts the specified command to be executed on the main thread,
470 * waits for the request to complete, and returns the result.
471 * @see #sendRequestAsync
472 */
473 private Object sendRequest(int command, Object argument) {
Wink Saville36469e72014-06-11 15:17:00 -0700474 return sendRequest(command, argument);
475 }
476
477 /**
478 * Posts the specified command to be executed on the main thread,
479 * waits for the request to complete, and returns the result.
480 * @see #sendRequestAsync
481 */
482 private Object sendRequest(int command, Object argument, Object argument2) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700483 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
484 throw new RuntimeException("This method will deadlock if called from the main thread.");
485 }
486
487 MainThreadRequest request = new MainThreadRequest(argument);
488 Message msg = mMainThreadHandler.obtainMessage(command, request);
489 msg.sendToTarget();
490
491 // Wait for the request to complete
492 synchronized (request) {
493 while (request.result == null) {
494 try {
495 request.wait();
496 } catch (InterruptedException e) {
497 // Do nothing, go back and wait until the request is complete
498 }
499 }
500 }
501 return request.result;
502 }
503
504 /**
505 * Asynchronous ("fire and forget") version of sendRequest():
506 * Posts the specified command to be executed on the main thread, and
507 * returns immediately.
508 * @see #sendRequest
509 */
510 private void sendRequestAsync(int command) {
511 mMainThreadHandler.sendEmptyMessage(command);
512 }
513
514 /**
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -0700515 * Same as {@link #sendRequestAsync(int)} except it takes an argument.
516 * @see {@link #sendRequest(int,Object)}
517 */
518 private void sendRequestAsync(int command, Object argument) {
519 MainThreadRequest request = new MainThreadRequest(argument);
520 Message msg = mMainThreadHandler.obtainMessage(command, request);
521 msg.sendToTarget();
522 }
523
524 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700525 * Initialize the singleton PhoneInterfaceManager instance.
526 * This is only done once, at startup, from PhoneApp.onCreate().
527 */
Santos Cordon406c0342013-08-28 00:07:47 -0700528 /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone,
Santos Cordon117fee72014-05-16 17:56:12 -0700529 CallHandlerServiceProxy callHandlerService) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700530 synchronized (PhoneInterfaceManager.class) {
531 if (sInstance == null) {
Santos Cordon117fee72014-05-16 17:56:12 -0700532 sInstance = new PhoneInterfaceManager(app, phone, callHandlerService);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700533 } else {
534 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
535 }
536 return sInstance;
537 }
538 }
539
540 /** Private constructor; @see init() */
Santos Cordon406c0342013-08-28 00:07:47 -0700541 private PhoneInterfaceManager(PhoneGlobals app, Phone phone,
Santos Cordon117fee72014-05-16 17:56:12 -0700542 CallHandlerServiceProxy callHandlerService) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700543 mApp = app;
544 mPhone = phone;
545 mCM = PhoneGlobals.getInstance().mCM;
546 mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
547 mMainThreadHandler = new MainThreadHandler();
Santos Cordon406c0342013-08-28 00:07:47 -0700548 mCallHandlerService = callHandlerService;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700549 publish();
550 }
551
552 private void publish() {
553 if (DBG) log("publish: " + this);
554
555 ServiceManager.addService("phone", this);
556 }
557
Wink Saville36469e72014-06-11 15:17:00 -0700558 // returns phone associated with the subId.
559 // getPhone(0) returns default phone in single SIM mode.
560 private Phone getPhone(long subId) {
561 // FIXME: hack for the moment
562 return mPhone;
563 // return PhoneUtils.getPhoneUsingSubId(subId);
564 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700565 //
566 // Implementation of the ITelephony interface.
567 //
568
569 public void dial(String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700570 dialUsingSubId(getPreferredVoiceSubscription(), number);
571 }
572
573 public void dialUsingSubId(long subId, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700574 if (DBG) log("dial: " + number);
575 // No permission check needed here: This is just a wrapper around the
576 // ACTION_DIAL intent, which is available to any app since it puts up
577 // the UI before it does anything.
578
579 String url = createTelUrl(number);
580 if (url == null) {
581 return;
582 }
583
584 // PENDING: should we just silently fail if phone is offhook or ringing?
Wink Saville36469e72014-06-11 15:17:00 -0700585 PhoneConstants.State state = mCM.getState(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700586 if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
587 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
588 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Wink Saville36469e72014-06-11 15:17:00 -0700589 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700590 mApp.startActivity(intent);
591 }
592 }
593
594 public void call(String callingPackage, String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700595 callUsingSubId(getPreferredVoiceSubscription(), callingPackage, number);
596 }
597
598 public void callUsingSubId(long subId, String callingPackage, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700599 if (DBG) log("call: " + number);
600
601 // This is just a wrapper around the ACTION_CALL intent, but we still
602 // need to do a permission check since we're calling startActivity()
603 // from the context of the phone app.
604 enforceCallPermission();
605
606 if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
607 != AppOpsManager.MODE_ALLOWED) {
608 return;
609 }
610
611 String url = createTelUrl(number);
612 if (url == null) {
613 return;
614 }
615
616 Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
Wink Saville36469e72014-06-11 15:17:00 -0700617 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700618 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
619 mApp.startActivity(intent);
620 }
621
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700622 /**
623 * End a call based on call state
624 * @return true is a call was ended
625 */
626 public boolean endCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700627 return endCallUsingSubId(getDefaultSubscription());
628 }
629
630 /**
631 * End a call based on the call state of the subId
632 * @return true is a call was ended
633 */
634 public boolean endCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700635 enforceCallPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700636 return (Boolean) sendRequest(CMD_END_CALL, subId, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700637 }
638
639 public void answerRingingCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700640 answerRingingCallUsingSubId(getDefaultSubscription());
641 }
642
643 public void answerRingingCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700644 if (DBG) log("answerRingingCall...");
645 // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
646 // but that can probably wait till the big TelephonyManager API overhaul.
647 // For now, protect this call with the MODIFY_PHONE_STATE permission.
648 enforceModifyPermission();
649 sendRequestAsync(CMD_ANSWER_RINGING_CALL);
650 }
651
652 /**
653 * Make the actual telephony calls to implement answerRingingCall().
654 * This should only be called from the main thread of the Phone app.
655 * @see #answerRingingCall
656 *
657 * TODO: it would be nice to return true if we answered the call, or
658 * false if there wasn't actually a ringing incoming call, or some
659 * other error occurred. (In other words, pass back the return value
660 * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
661 * But that would require calling this method via sendRequest() rather
662 * than sendRequestAsync(), and right now we don't actually *need* that
663 * return value, so let's just return void for now.
664 */
665 private void answerRingingCallInternal() {
666 final boolean hasRingingCall = !mPhone.getRingingCall().isIdle();
667 if (hasRingingCall) {
668 final boolean hasActiveCall = !mPhone.getForegroundCall().isIdle();
669 final boolean hasHoldingCall = !mPhone.getBackgroundCall().isIdle();
670 if (hasActiveCall && hasHoldingCall) {
671 // Both lines are in use!
672 // TODO: provide a flag to let the caller specify what
673 // policy to use if both lines are in use. (The current
674 // behavior is hardwired to "answer incoming, end ongoing",
675 // which is how the CALL button is specced to behave.)
676 PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
677 return;
678 } else {
679 // answerCall() will automatically hold the current active
680 // call, if there is one.
681 PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
682 return;
683 }
684 } else {
685 // No call was ringing.
686 return;
687 }
688 }
689
690 public void silenceRinger() {
691 if (DBG) log("silenceRinger...");
692 // TODO: find a more appropriate permission to check here.
693 // (That can probably wait till the big TelephonyManager API overhaul.
694 // For now, protect this call with the MODIFY_PHONE_STATE permission.)
695 enforceModifyPermission();
696 sendRequestAsync(CMD_SILENCE_RINGER);
697 }
698
699 /**
700 * Internal implemenation of silenceRinger().
701 * This should only be called from the main thread of the Phone app.
702 * @see #silenceRinger
703 */
704 private void silenceRingerInternal() {
705 if ((mCM.getState() == PhoneConstants.State.RINGING)
706 && mApp.notifier.isRinging()) {
707 // Ringer is actually playing, so silence it.
708 if (DBG) log("silenceRingerInternal: silencing...");
709 mApp.notifier.silenceRinger();
710 }
711 }
712
713 public boolean isOffhook() {
Wink Saville36469e72014-06-11 15:17:00 -0700714 return isOffhookUsingSubId(getDefaultSubscription());
715 }
716
717 public boolean isOffhookUsingSubId(long subId) {
718 return (getPhone(subId).getState() == PhoneConstants.State.OFFHOOK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700719 }
720
721 public boolean isRinging() {
Wink Saville36469e72014-06-11 15:17:00 -0700722 return (isRingingUsingSubId(getDefaultSubscription()));
723 }
724
725 public boolean isRingingUsingSubId(long subId) {
726 return (getPhone(subId).getState() == PhoneConstants.State.RINGING);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700727 }
728
729 public boolean isIdle() {
Wink Saville36469e72014-06-11 15:17:00 -0700730 return isIdleUsingSubId(getDefaultSubscription());
731 }
732
733 public boolean isIdleUsingSubId(long subId) {
734 return (getPhone(subId).getState() == PhoneConstants.State.IDLE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700735 }
736
737 public boolean isSimPinEnabled() {
738 enforceReadPermission();
739 return (PhoneGlobals.getInstance().isSimPinEnabled());
740 }
741
742 public boolean supplyPin(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700743 return supplyPinUsingSubId(getDefaultSubscription(), pin);
744 }
745
746 public boolean supplyPinUsingSubId(long subId, String pin) {
747 int [] resultArray = supplyPinReportResultUsingSubId(subId, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700748 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
749 }
750
751 public boolean supplyPuk(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700752 return supplyPukUsingSubId(getDefaultSubscription(), puk, pin);
753 }
754
755 public boolean supplyPukUsingSubId(long subId, String puk, String pin) {
756 int [] resultArray = supplyPukReportResultUsingSubId(subId, puk, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700757 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
758 }
759
760 /** {@hide} */
761 public int[] supplyPinReportResult(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700762 return supplyPinReportResultUsingSubId(getDefaultSubscription(), pin);
763 }
764
765 public int[] supplyPinReportResultUsingSubId(long subId, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700766 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700767 final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700768 checkSimPin.start();
769 return checkSimPin.unlockSim(null, pin);
770 }
771
Wink Saville9de0f752013-10-22 19:04:03 -0700772 /** {@hide} */
773 public int[] supplyPukReportResult(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700774 return supplyPukReportResultUsingSubId(getDefaultSubscription(), puk, pin);
775 }
776
777 public int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700778 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700779 final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700780 checkSimPuk.start();
781 return checkSimPuk.unlockSim(puk, pin);
782 }
783
784 /**
Wink Saville9de0f752013-10-22 19:04:03 -0700785 * Helper thread to turn async call to SimCard#supplyPin into
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700786 * a synchronous one.
787 */
788 private static class UnlockSim extends Thread {
789
790 private final IccCard mSimCard;
791
792 private boolean mDone = false;
Wink Saville9de0f752013-10-22 19:04:03 -0700793 private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
794 private int mRetryCount = -1;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700795
796 // For replies from SimCard interface
797 private Handler mHandler;
798
799 // For async handler to identify request type
800 private static final int SUPPLY_PIN_COMPLETE = 100;
801
802 public UnlockSim(IccCard simCard) {
803 mSimCard = simCard;
804 }
805
806 @Override
807 public void run() {
808 Looper.prepare();
809 synchronized (UnlockSim.this) {
810 mHandler = new Handler() {
811 @Override
812 public void handleMessage(Message msg) {
813 AsyncResult ar = (AsyncResult) msg.obj;
814 switch (msg.what) {
815 case SUPPLY_PIN_COMPLETE:
816 Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
817 synchronized (UnlockSim.this) {
Wink Saville9de0f752013-10-22 19:04:03 -0700818 mRetryCount = msg.arg1;
819 if (ar.exception != null) {
820 if (ar.exception instanceof CommandException &&
821 ((CommandException)(ar.exception)).getCommandError()
822 == CommandException.Error.PASSWORD_INCORRECT) {
823 mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
824 } else {
825 mResult = PhoneConstants.PIN_GENERAL_FAILURE;
826 }
827 } else {
828 mResult = PhoneConstants.PIN_RESULT_SUCCESS;
829 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700830 mDone = true;
831 UnlockSim.this.notifyAll();
832 }
833 break;
834 }
835 }
836 };
837 UnlockSim.this.notifyAll();
838 }
839 Looper.loop();
840 }
841
842 /*
843 * Use PIN or PUK to unlock SIM card
844 *
845 * If PUK is null, unlock SIM card with PIN
846 *
847 * If PUK is not null, unlock SIM card with PUK and set PIN code
848 */
Wink Saville9de0f752013-10-22 19:04:03 -0700849 synchronized int[] unlockSim(String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700850
851 while (mHandler == null) {
852 try {
853 wait();
854 } catch (InterruptedException e) {
855 Thread.currentThread().interrupt();
856 }
857 }
858 Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
859
860 if (puk == null) {
861 mSimCard.supplyPin(pin, callback);
862 } else {
863 mSimCard.supplyPuk(puk, pin, callback);
864 }
865
866 while (!mDone) {
867 try {
868 Log.d(LOG_TAG, "wait for done");
869 wait();
870 } catch (InterruptedException e) {
871 // Restore the interrupted status
872 Thread.currentThread().interrupt();
873 }
874 }
875 Log.d(LOG_TAG, "done");
Wink Saville9de0f752013-10-22 19:04:03 -0700876 int[] resultArray = new int[2];
877 resultArray[0] = mResult;
878 resultArray[1] = mRetryCount;
879 return resultArray;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700880 }
881 }
882
883 public void updateServiceLocation() {
Wink Saville36469e72014-06-11 15:17:00 -0700884 updateServiceLocationUsingSubId(getDefaultSubscription());
885
886 }
887
888 public void updateServiceLocationUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700889 // No permission check needed here: this call is harmless, and it's
890 // needed for the ServiceState.requestStateUpdate() call (which is
891 // already intentionally exposed to 3rd parties.)
Wink Saville36469e72014-06-11 15:17:00 -0700892 getPhone(subId).updateServiceLocation();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700893 }
894
895 public boolean isRadioOn() {
Wink Saville36469e72014-06-11 15:17:00 -0700896 return isRadioOnUsingSubId(getDefaultSubscription());
897 }
898
899 public boolean isRadioOnUsingSubId(long subId) {
900 return getPhone(subId).getServiceState().getState() != ServiceState.STATE_POWER_OFF;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700901 }
902
903 public void toggleRadioOnOff() {
Wink Saville36469e72014-06-11 15:17:00 -0700904 toggleRadioOnOffUsingSubId(getDefaultSubscription());
905
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700906 }
Wink Saville36469e72014-06-11 15:17:00 -0700907
908 public void toggleRadioOnOffUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700909 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700910 getPhone(subId).setRadioPower(!isRadioOnUsingSubId(subId));
911 }
912
913 public boolean setRadio(boolean turnOn) {
914 return setRadioUsingSubId(getDefaultSubscription(), turnOn);
915 }
916
917 public boolean setRadioUsingSubId(long subId, boolean turnOn) {
918 enforceModifyPermission();
919 if ((getPhone(subId).getServiceState().getState() !=
920 ServiceState.STATE_POWER_OFF) != turnOn) {
921 toggleRadioOnOffUsingSubId(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700922 }
923 return true;
924 }
Wink Saville36469e72014-06-11 15:17:00 -0700925
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700926 public boolean setRadioPower(boolean turnOn) {
Wink Saville36469e72014-06-11 15:17:00 -0700927 return setRadioPowerUsingSubId(getDefaultSubscription(), turnOn);
928 }
929
930 public boolean setRadioPowerUsingSubId(long subId, boolean turnOn) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700931 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700932 getPhone(subId).setRadioPower(turnOn);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700933 return true;
934 }
935
Wink Saville36469e72014-06-11 15:17:00 -0700936 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700937 public boolean enableDataConnectivity() {
938 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700939 long subId = SubscriptionManager.getDefaultDataSubId();
940 getPhone(subId).setDataEnabled(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700941 return true;
942 }
943
Wink Saville36469e72014-06-11 15:17:00 -0700944 public int enableApnTypeUsingSub(long subId, String type) {
945 enforceModifyPermission();
946 log("enableApnTypeUsingSub subId = " + subId);
947 return DctController.getInstance().enableApnType(subId, type);
948 }
949
950 public int disableApnTypeUsingSub(long subId, String type) {
951 enforceModifyPermission();
952 log("enableApnTypeUsingSub subId = " + subId);
953 return DctController.getInstance().disableApnType(subId, type);
954 }
955
956 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700957 public int enableApnType(String type) {
958 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700959 long subId = SubscriptionManager.getDefaultDataSubId();
960 return getPhone(subId).enableApnType(type);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700961 }
962
Wink Saville36469e72014-06-11 15:17:00 -0700963 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700964 public int disableApnType(String type) {
965 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700966 long subId = SubscriptionManager.getDefaultDataSubId();
967 return getPhone(subId).disableApnType(type);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700968 }
969
Wink Saville36469e72014-06-11 15:17:00 -0700970 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700971 public boolean disableDataConnectivity() {
972 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700973 long subId = SubscriptionManager.getDefaultDataSubId();
974 getPhone(subId).setDataEnabled(false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700975 return true;
976 }
977
Wink Saville36469e72014-06-11 15:17:00 -0700978 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700979 public boolean isDataConnectivityPossible() {
Wink Saville36469e72014-06-11 15:17:00 -0700980 long subId = SubscriptionManager.getDefaultDataSubId();
981 return getPhone(subId).isDataConnectivityPossible();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700982 }
983
984 public boolean handlePinMmi(String dialString) {
Wink Saville36469e72014-06-11 15:17:00 -0700985 return handlePinMmiUsingSubId(getDefaultSubscription(), dialString);
986 }
987
988 public boolean handlePinMmiUsingSubId(long subId, String dialString) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700989 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700990 return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700991 }
992
993 public void cancelMissedCallsNotification() {
Wink Saville36469e72014-06-11 15:17:00 -0700994 cancelMissedCallsNotificationUsingSubId(getDefaultSubscription());
995 }
996
997 public void cancelMissedCallsNotificationUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700998 enforceModifyPermission();
999 mApp.notificationMgr.cancelMissedCallNotification();
1000 }
1001
1002 public int getCallState() {
Wink Saville36469e72014-06-11 15:17:00 -07001003 return getCallStateUsingSubId(getDefaultSubscription());
1004 }
1005
1006 public int getCallStateUsingSubId(long subId) {
1007 return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001008 }
1009
1010 public int getDataState() {
Wink Saville36469e72014-06-11 15:17:00 -07001011 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1012 return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001013 }
1014
1015 public int getDataActivity() {
Wink Saville36469e72014-06-11 15:17:00 -07001016 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1017 return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001018 }
1019
1020 @Override
1021 public Bundle getCellLocation() {
1022 try {
1023 mApp.enforceCallingOrSelfPermission(
1024 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1025 } catch (SecurityException e) {
1026 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1027 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1028 // is the weaker precondition
1029 mApp.enforceCallingOrSelfPermission(
1030 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1031 }
1032
Jake Hambye994d462014-02-03 13:10:13 -08001033 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001034 if (DBG_LOC) log("getCellLocation: is active user");
1035 Bundle data = new Bundle();
1036 mPhone.getCellLocation().fillInNotifierBundle(data);
1037 return data;
1038 } else {
1039 if (DBG_LOC) log("getCellLocation: suppress non-active user");
1040 return null;
1041 }
1042 }
1043
1044 @Override
1045 public void enableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001046 enableLocationUpdatesUsingSubId(getDefaultSubscription());
1047 }
1048
1049 public void enableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001050 mApp.enforceCallingOrSelfPermission(
1051 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001052 getPhone(subId).enableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001053 }
1054
1055 @Override
1056 public void disableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001057 disableLocationUpdatesUsingSubId(getDefaultSubscription());
1058 }
1059
1060 public void disableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001061 mApp.enforceCallingOrSelfPermission(
1062 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001063 getPhone(subId).disableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001064 }
1065
1066 @Override
1067 @SuppressWarnings("unchecked")
1068 public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1069 try {
1070 mApp.enforceCallingOrSelfPermission(
1071 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1072 } catch (SecurityException e) {
1073 // If we have ACCESS_FINE_LOCATION permission, skip the check
1074 // for ACCESS_COARSE_LOCATION
1075 // A failure should throw the SecurityException from
1076 // ACCESS_COARSE_LOCATION since this is the weaker precondition
1077 mApp.enforceCallingOrSelfPermission(
1078 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1079 }
1080
1081 if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1082 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1083 return null;
1084 }
Jake Hambye994d462014-02-03 13:10:13 -08001085 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001086 if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1087
1088 ArrayList<NeighboringCellInfo> cells = null;
1089
1090 try {
1091 cells = (ArrayList<NeighboringCellInfo>) sendRequest(
Wink Saville36469e72014-06-11 15:17:00 -07001092 CMD_HANDLE_NEIGHBORING_CELL, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001093 } catch (RuntimeException e) {
Wink Saville36469e72014-06-11 15:17:00 -07001094 Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001095 }
1096 return cells;
1097 } else {
1098 if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1099 return null;
1100 }
1101 }
1102
1103
1104 @Override
1105 public List<CellInfo> getAllCellInfo() {
1106 try {
1107 mApp.enforceCallingOrSelfPermission(
1108 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1109 } catch (SecurityException e) {
1110 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1111 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1112 // is the weaker precondition
1113 mApp.enforceCallingOrSelfPermission(
1114 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1115 }
1116
Jake Hambye994d462014-02-03 13:10:13 -08001117 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001118 if (DBG_LOC) log("getAllCellInfo: is active user");
1119 return mPhone.getAllCellInfo();
1120 } else {
1121 if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1122 return null;
1123 }
1124 }
1125
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -07001126 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001127 public void setCellInfoListRate(int rateInMillis) {
1128 mPhone.setCellInfoListRate(rateInMillis);
1129 }
1130
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001131 //
1132 // Internal helper methods.
1133 //
1134
Jake Hambye994d462014-02-03 13:10:13 -08001135 private static boolean checkIfCallerIsSelfOrForegroundUser() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001136 boolean ok;
1137
1138 boolean self = Binder.getCallingUid() == Process.myUid();
1139 if (!self) {
1140 // Get the caller's user id then clear the calling identity
1141 // which will be restored in the finally clause.
1142 int callingUser = UserHandle.getCallingUserId();
1143 long ident = Binder.clearCallingIdentity();
1144
1145 try {
1146 // With calling identity cleared the current user is the foreground user.
1147 int foregroundUser = ActivityManager.getCurrentUser();
1148 ok = (foregroundUser == callingUser);
1149 if (DBG_LOC) {
1150 log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1151 + " callingUser=" + callingUser + " ok=" + ok);
1152 }
1153 } catch (Exception ex) {
1154 if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1155 ok = false;
1156 } finally {
1157 Binder.restoreCallingIdentity(ident);
1158 }
1159 } else {
1160 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1161 ok = true;
1162 }
1163 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1164 return ok;
1165 }
1166
1167 /**
1168 * Make sure the caller has the READ_PHONE_STATE permission.
1169 *
1170 * @throws SecurityException if the caller does not have the required permission
1171 */
1172 private void enforceReadPermission() {
1173 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
1174 }
1175
1176 /**
1177 * Make sure the caller has the MODIFY_PHONE_STATE permission.
1178 *
1179 * @throws SecurityException if the caller does not have the required permission
1180 */
1181 private void enforceModifyPermission() {
1182 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1183 }
1184
1185 /**
1186 * Make sure the caller has the CALL_PHONE permission.
1187 *
1188 * @throws SecurityException if the caller does not have the required permission
1189 */
1190 private void enforceCallPermission() {
1191 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1192 }
1193
Shishir Agrawal566b7612013-10-28 14:41:00 -07001194 /**
Gabriel Peal36ebb0d2014-03-20 09:20:43 -07001195 * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1196 *
1197 * @throws SecurityException if the caller does not have the required permission
1198 */
1199 private void enforcePrivilegedPhoneStatePermission() {
1200 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1201 null);
1202 }
1203
1204 /**
Shishir Agrawal566b7612013-10-28 14:41:00 -07001205 * Make sure the caller has SIM_COMMUNICATION permission.
1206 *
1207 * @throws SecurityException if the caller does not have the required permission.
1208 */
1209 private void enforceSimCommunicationPermission() {
1210 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.SIM_COMMUNICATION, null);
1211 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001212
1213 private String createTelUrl(String number) {
1214 if (TextUtils.isEmpty(number)) {
1215 return null;
1216 }
1217
Jake Hambye994d462014-02-03 13:10:13 -08001218 return "tel:" + number;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001219 }
1220
Ihab Awadf9e92732013-12-05 18:02:52 -08001221 private static void log(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001222 Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1223 }
1224
Ihab Awadf9e92732013-12-05 18:02:52 -08001225 private static void loge(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001226 Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1227 }
1228
1229 public int getActivePhoneType() {
Wink Saville36469e72014-06-11 15:17:00 -07001230 return getActivePhoneTypeUsingSubId(getDefaultSubscription());
1231 }
1232
1233 public int getActivePhoneTypeUsingSubId(long subId) {
1234 return getPhone(subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001235 }
1236
1237 /**
1238 * Returns the CDMA ERI icon index to display
1239 */
1240 public int getCdmaEriIconIndex() {
Wink Saville36469e72014-06-11 15:17:00 -07001241 return getCdmaEriIconIndexUsingSubId(getDefaultSubscription());
1242
1243 }
1244
1245 public int getCdmaEriIconIndexUsingSubId(long subId) {
1246 return getPhone(subId).getCdmaEriIconIndex();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001247 }
1248
1249 /**
1250 * Returns the CDMA ERI icon mode,
1251 * 0 - ON
1252 * 1 - FLASHING
1253 */
1254 public int getCdmaEriIconMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001255 return getCdmaEriIconModeUsingSubId(getDefaultSubscription());
1256 }
1257
1258 public int getCdmaEriIconModeUsingSubId(long subId) {
1259 return getPhone(subId).getCdmaEriIconMode();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001260 }
1261
1262 /**
1263 * Returns the CDMA ERI text,
1264 */
1265 public String getCdmaEriText() {
Wink Saville36469e72014-06-11 15:17:00 -07001266 return getCdmaEriTextUsingSubId(getDefaultSubscription());
1267 }
1268
1269 public String getCdmaEriTextUsingSubId(long subId) {
1270 return getPhone(subId).getCdmaEriText();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001271 }
1272
1273 /**
1274 * Returns true if CDMA provisioning needs to run.
1275 */
1276 public boolean needsOtaServiceProvisioning() {
1277 return mPhone.needsOtaServiceProvisioning();
1278 }
1279
1280 /**
1281 * Returns the unread count of voicemails
1282 */
1283 public int getVoiceMessageCount() {
Wink Saville36469e72014-06-11 15:17:00 -07001284 return getVoiceMessageCountUsingSubId(getDefaultSubscription());
1285 }
1286
1287 /**
1288 * Returns the unread count of voicemails for a subId
1289 */
1290 public int getVoiceMessageCountUsingSubId( long subId) {
1291 return getPhone(subId).getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001292 }
1293
1294 /**
1295 * Returns the data network type
1296 *
1297 * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1298 */
1299 @Override
1300 public int getNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001301 return getNetworkTypeUsingSubId(getDefaultSubscription());
1302 }
1303
1304 /**
1305 * Returns the network type for a subId
1306 */
1307 @Override
1308 public int getNetworkTypeUsingSubId(long subId) {
1309 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001310 }
1311
1312 /**
1313 * Returns the data network type
1314 */
1315 @Override
1316 public int getDataNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001317 return getDataNetworkTypeUsingSubId(getDefaultSubscription());
1318 }
1319
1320 /**
1321 * Returns the data network type for a subId
1322 */
1323 @Override
1324 public int getDataNetworkTypeUsingSubId(long subId) {
1325 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001326 }
1327
1328 /**
1329 * Returns the data network type
1330 */
1331 @Override
1332 public int getVoiceNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001333 return getVoiceNetworkTypeUsingSubId(getDefaultSubscription());
1334 }
1335
1336 /**
1337 * Returns the Voice network type for a subId
1338 */
1339 @Override
1340 public int getVoiceNetworkTypeUsingSubId(long subId) {
1341 return getPhone(subId).getServiceState().getVoiceNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001342 }
1343
1344 /**
1345 * @return true if a ICC card is present
1346 */
1347 public boolean hasIccCard() {
Wink Saville36469e72014-06-11 15:17:00 -07001348 // FIXME Make changes to pass defaultSimId of type int
1349 return hasIccCardUsingSlotId(getDefaultSubscription());
1350 }
1351
1352 /**
1353 * @return true if a ICC card is present for a slotId
1354 */
1355 public boolean hasIccCardUsingSlotId(long slotId) {
1356 return getPhone(slotId).getIccCard().hasIccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001357 }
1358
1359 /**
1360 * Return if the current radio is LTE on CDMA. This
1361 * is a tri-state return value as for a period of time
1362 * the mode may be unknown.
1363 *
1364 * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
Jake Hambye994d462014-02-03 13:10:13 -08001365 * or {@link Phone#LTE_ON_CDMA_TRUE}
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001366 */
1367 public int getLteOnCdmaMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001368 return getLteOnCdmaModeUsingSubId(getDefaultSubscription());
1369 }
1370
1371 public int getLteOnCdmaModeUsingSubId(long subId) {
1372 return getPhone(subId).getLteOnCdmaMode();
1373 }
1374
1375 public void setPhone(Phone phone) {
1376 mPhone = phone;
1377 }
1378
1379 /**
1380 * {@hide}
1381 * Returns Default subId, 0 in the case of single standby.
1382 */
1383 private long getDefaultSubscription() {
1384 return SubscriptionManager.getDefaultSubId();
1385 }
1386
1387 private long getPreferredVoiceSubscription() {
1388 return SubscriptionManager.getDefaultVoiceSubId();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001389 }
Ihab Awadf2177b72013-11-25 13:33:23 -08001390
1391 /**
1392 * @see android.telephony.TelephonyManager.WifiCallingChoices
1393 */
1394 public int getWhenToMakeWifiCalls() {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001395 return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1396 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
Ihab Awadf2177b72013-11-25 13:33:23 -08001397 }
1398
1399 /**
1400 * @see android.telephony.TelephonyManager.WifiCallingChoices
1401 */
1402 public void setWhenToMakeWifiCalls(int preference) {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001403 if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1404 Settings.System.putInt(mPhone.getContext().getContentResolver(),
1405 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
Ihab Awadf9e92732013-12-05 18:02:52 -08001406 }
1407
Sailesh Nepald1e68152013-12-12 19:08:02 -08001408 private static int getWhenToMakeWifiCallsDefaultPreference() {
1409 // TODO(sail): Use a build property to choose this value.
Evan Charlton9829e882013-12-19 15:30:38 -08001410 return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
Ihab Awadf2177b72013-11-25 13:33:23 -08001411 }
Shishir Agrawal69f68122013-12-16 17:25:49 -08001412
Shishir Agrawal566b7612013-10-28 14:41:00 -07001413 @Override
1414 public int iccOpenLogicalChannel(String AID) {
1415 enforceSimCommunicationPermission();
1416
1417 if (DBG) log("iccOpenLogicalChannel: " + AID);
1418 Integer channel = (Integer)sendRequest(CMD_OPEN_CHANNEL, AID);
1419 if (DBG) log("iccOpenLogicalChannel: " + channel);
Jake Hambye994d462014-02-03 13:10:13 -08001420 return channel;
Shishir Agrawal566b7612013-10-28 14:41:00 -07001421 }
1422
1423 @Override
1424 public boolean iccCloseLogicalChannel(int channel) {
1425 enforceSimCommunicationPermission();
1426
1427 if (DBG) log("iccCloseLogicalChannel: " + channel);
1428 if (channel < 0) {
1429 return false;
1430 }
Jake Hambye994d462014-02-03 13:10:13 -08001431 Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
Shishir Agrawal566b7612013-10-28 14:41:00 -07001432 if (DBG) log("iccCloseLogicalChannel: " + success);
1433 return success;
1434 }
1435
1436 @Override
1437 public String iccTransmitApduLogicalChannel(int channel, int cla,
1438 int command, int p1, int p2, int p3, String data) {
1439 enforceSimCommunicationPermission();
1440
1441 if (DBG) {
1442 log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1443 " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1444 " data=" + data);
1445 }
1446
1447 if (channel < 0) {
1448 return "";
1449 }
1450
1451 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU,
1452 new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1453 if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1454
1455 // If the payload is null, there was an error. Indicate that by returning
1456 // an empty string.
1457 if (response.payload == null) {
1458 return "";
1459 }
1460
1461 // Append the returned status code to the end of the response payload.
1462 String s = Integer.toHexString(
1463 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1464 s = IccUtils.bytesToHexString(response.payload) + s;
1465 return s;
1466 }
Jake Hambye994d462014-02-03 13:10:13 -08001467
Evan Charltonc66da362014-05-16 14:06:40 -07001468 @Override
1469 public String sendEnvelopeWithStatus(String content) {
1470 enforceSimCommunicationPermission();
1471
1472 IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
1473 if (response.payload == null) {
1474 return "";
1475 }
1476
1477 // Append the returned status code to the end of the response payload.
1478 String s = Integer.toHexString(
1479 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1480 s = IccUtils.bytesToHexString(response.payload) + s;
1481 return s;
1482 }
1483
Jake Hambye994d462014-02-03 13:10:13 -08001484 /**
1485 * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1486 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1487 *
1488 * @param itemID the ID of the item to read
1489 * @return the NV item as a String, or null on error.
1490 */
1491 @Override
1492 public String nvReadItem(int itemID) {
1493 enforceModifyPermission();
1494 if (DBG) log("nvReadItem: item " + itemID);
1495 String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
1496 if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
1497 return value;
1498 }
1499
1500 /**
1501 * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1502 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1503 *
1504 * @param itemID the ID of the item to read
1505 * @param itemValue the value to write, as a String
1506 * @return true on success; false on any failure
1507 */
1508 @Override
1509 public boolean nvWriteItem(int itemID, String itemValue) {
1510 enforceModifyPermission();
1511 if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
1512 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
1513 new Pair<Integer, String>(itemID, itemValue));
1514 if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
1515 return success;
1516 }
1517
1518 /**
1519 * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
1520 * Used for device configuration by some CDMA operators.
1521 *
1522 * @param preferredRoamingList byte array containing the new PRL
1523 * @return true on success; false on any failure
1524 */
1525 @Override
1526 public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
1527 enforceModifyPermission();
1528 if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
1529 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
1530 if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
1531 return success;
1532 }
1533
1534 /**
1535 * Perform the specified type of NV config reset.
1536 * Used for device configuration by some CDMA operators.
1537 *
1538 * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
1539 * @return true on success; false on any failure
1540 */
1541 @Override
1542 public boolean nvResetConfig(int resetType) {
1543 enforceModifyPermission();
1544 if (DBG) log("nvResetConfig: type " + resetType);
1545 Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
1546 if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
1547 return success;
1548 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001549
1550 /**
Wink Saville36469e72014-06-11 15:17:00 -07001551 * {@hide}
1552 * Returns Default sim, 0 in the case of single standby.
1553 */
1554 public int getDefaultSim() {
1555 //TODO Need to get it from Telephony Devcontroller
1556 return 0;
1557 }
1558
1559 public String[] getPcscfAddress() {
1560 enforceReadPermission();
1561 return mPhone.getPcscfAddress();
1562 }
1563
1564 public void setImsRegistrationState(boolean registered) {
1565 enforceModifyPermission();
1566 mPhone.setImsRegistrationState(registered);
1567 }
1568
1569 /**
Jake Hamby7c27be32014-03-03 13:25:59 -08001570 * Get the preferred network type.
1571 * Used for device configuration by some CDMA operators.
1572 *
1573 * @return the preferred network type, defined in RILConstants.java.
1574 */
1575 @Override
1576 public int getPreferredNetworkType() {
1577 enforceModifyPermission();
1578 if (DBG) log("getPreferredNetworkType");
1579 int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null);
1580 int networkType = (result != null ? result[0] : -1);
1581 if (DBG) log("getPreferredNetworkType: " + networkType);
1582 return networkType;
1583 }
1584
1585 /**
1586 * Set the preferred network type.
1587 * Used for device configuration by some CDMA operators.
1588 *
1589 * @param networkType the preferred network type, defined in RILConstants.java.
1590 * @return true on success; false on any failure.
1591 */
1592 @Override
1593 public boolean setPreferredNetworkType(int networkType) {
1594 enforceModifyPermission();
1595 if (DBG) log("setPreferredNetworkType: type " + networkType);
1596 Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType);
1597 if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
1598 return success;
1599 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001600
1601 /**
1602 * Set mobile data enabled
1603 * Used by the user through settings etc to turn on/off mobile data
1604 *
1605 * @param enable {@code true} turn turn data on, else {@code false}
1606 */
1607 @Override
1608 public void setDataEnabled(boolean enable) {
1609 enforceModifyPermission();
1610 mPhone.setDataEnabled(enable);
1611 }
1612
1613 /**
Robert Greenwalt646120a2014-05-23 11:54:03 -07001614 * Get whether mobile data is enabled.
1615 *
1616 * Note that this used to be available from ConnectivityService, gated by
1617 * ACCESS_NETWORK_STATE permission, so this will accept either that or
1618 * our MODIFY_PHONE_STATE.
Robert Greenwalted86e582014-05-21 20:03:20 -07001619 *
1620 * @return {@code true} if data is enabled else {@code false}
1621 */
1622 @Override
1623 public boolean getDataEnabled() {
Robert Greenwalt646120a2014-05-23 11:54:03 -07001624 try {
1625 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
1626 null);
1627 } catch (Exception e) {
1628 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
1629 null);
1630 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001631 return mPhone.getDataEnabled();
1632 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001633}