blob: 7f75ab2a49b4af71ed38b1f585b4b28f2da1ec6b [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;
Junda Liu787bc7e2014-06-30 13:38:02 -0700108 private static final int CMD_SET_CDMA_SUBSCRIPTION = 27;
109 private static final int EVENT_SET_CDMA_SUBSCRIPTION_DONE = 28;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700110
111 /** The singleton instance. */
112 private static PhoneInterfaceManager sInstance;
113
114 PhoneGlobals mApp;
115 Phone mPhone;
116 CallManager mCM;
117 AppOpsManager mAppOps;
118 MainThreadHandler mMainThreadHandler;
Santos Cordon406c0342013-08-28 00:07:47 -0700119 CallHandlerServiceProxy mCallHandlerService;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700120
121 /**
Shishir Agrawal566b7612013-10-28 14:41:00 -0700122 * A request object to use for transmitting data to an ICC.
123 */
124 private static final class IccAPDUArgument {
125 public int channel, cla, command, p1, p2, p3;
126 public String data;
127
128 public IccAPDUArgument(int channel, int cla, int command,
129 int p1, int p2, int p3, String data) {
130 this.channel = channel;
131 this.cla = cla;
132 this.command = command;
133 this.p1 = p1;
134 this.p2 = p2;
135 this.p3 = p3;
136 this.data = data;
137 }
138 }
139
140 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700141 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
142 * request after sending. The main thread will notify the request when it is complete.
143 */
144 private static final class MainThreadRequest {
145 /** The argument to use for the request */
146 public Object argument;
147 /** The result of the request that is run on the main thread */
148 public Object result;
149
150 public MainThreadRequest(Object argument) {
151 this.argument = argument;
152 }
153 }
154
Sailesh Nepalcc0375f2013-11-13 09:15:18 -0800155 private static final class IncomingThirdPartyCallArgs {
156 public final ComponentName component;
157 public final String callId;
158 public final String callerDisplayName;
159
160 public IncomingThirdPartyCallArgs(ComponentName component, String callId,
161 String callerDisplayName) {
162 this.component = component;
163 this.callId = callId;
164 this.callerDisplayName = callerDisplayName;
165 }
166 }
167
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700168 /**
169 * A handler that processes messages on the main thread in the phone process. Since many
170 * of the Phone calls are not thread safe this is needed to shuttle the requests from the
171 * inbound binder threads to the main thread in the phone process. The Binder thread
172 * may provide a {@link MainThreadRequest} object in the msg.obj field that they are waiting
173 * on, which will be notified when the operation completes and will contain the result of the
174 * request.
175 *
176 * <p>If a MainThreadRequest object is provided in the msg.obj field,
177 * note that request.result must be set to something non-null for the calling thread to
178 * unblock.
179 */
180 private final class MainThreadHandler extends Handler {
181 @Override
182 public void handleMessage(Message msg) {
183 MainThreadRequest request;
184 Message onCompleted;
185 AsyncResult ar;
186
187 switch (msg.what) {
188 case CMD_HANDLE_PIN_MMI:
189 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800190 request.result = mPhone.handlePinMmi((String) request.argument);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700191 // Wake up the requesting thread
192 synchronized (request) {
193 request.notifyAll();
194 }
195 break;
196
197 case CMD_HANDLE_NEIGHBORING_CELL:
198 request = (MainThreadRequest) msg.obj;
199 onCompleted = obtainMessage(EVENT_NEIGHBORING_CELL_DONE,
200 request);
201 mPhone.getNeighboringCids(onCompleted);
202 break;
203
204 case EVENT_NEIGHBORING_CELL_DONE:
205 ar = (AsyncResult) msg.obj;
206 request = (MainThreadRequest) ar.userObj;
207 if (ar.exception == null && ar.result != null) {
208 request.result = ar.result;
209 } else {
210 // create an empty list to notify the waiting thread
Jake Hambye994d462014-02-03 13:10:13 -0800211 request.result = new ArrayList<NeighboringCellInfo>(0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700212 }
213 // Wake up the requesting thread
214 synchronized (request) {
215 request.notifyAll();
216 }
217 break;
218
219 case CMD_ANSWER_RINGING_CALL:
220 answerRingingCallInternal();
221 break;
222
223 case CMD_SILENCE_RINGER:
224 silenceRingerInternal();
225 break;
226
227 case CMD_END_CALL:
228 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800229 boolean hungUp;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700230 int phoneType = mPhone.getPhoneType();
231 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
232 // CDMA: If the user presses the Power button we treat it as
233 // ending the complete call session
234 hungUp = PhoneUtils.hangupRingingAndActive(mPhone);
235 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
236 // GSM: End the call as per the Phone state
237 hungUp = PhoneUtils.hangup(mCM);
238 } else {
239 throw new IllegalStateException("Unexpected phone type: " + phoneType);
240 }
241 if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up"));
242 request.result = hungUp;
243 // Wake up the requesting thread
244 synchronized (request) {
245 request.notifyAll();
246 }
247 break;
248
Shishir Agrawal566b7612013-10-28 14:41:00 -0700249 case CMD_TRANSMIT_APDU:
250 request = (MainThreadRequest) msg.obj;
251 IccAPDUArgument argument = (IccAPDUArgument) request.argument;
252 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_DONE, request);
253 UiccController.getInstance().getUiccCard().iccTransmitApduLogicalChannel(
254 argument.channel, argument.cla, argument.command,
255 argument.p1, argument.p2, argument.p3, argument.data,
256 onCompleted);
257 break;
258
259 case EVENT_TRANSMIT_APDU_DONE:
260 ar = (AsyncResult) msg.obj;
261 request = (MainThreadRequest) ar.userObj;
262 if (ar.exception == null && ar.result != null) {
263 request.result = ar.result;
264 } else {
265 request.result = new IccIoResult(0x6F, 0, (byte[])null);
266 if (ar.result == null) {
267 loge("iccTransmitApduLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800268 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700269 loge("iccTransmitApduLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800270 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700271 } else {
272 loge("iccTransmitApduLogicalChannel: Unknown exception");
273 }
274 }
275 synchronized (request) {
276 request.notifyAll();
277 }
278 break;
279
Derek Tan4d5e5c12014-02-04 11:54:58 -0800280 case CMD_SEND_ENVELOPE:
281 request = (MainThreadRequest) msg.obj;
282 onCompleted = obtainMessage(EVENT_SEND_ENVELOPE_DONE, request);
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700283 UiccController.getInstance().getUiccCard().sendEnvelopeWithStatus(
Derek Tan4d5e5c12014-02-04 11:54:58 -0800284 (String)request.argument, onCompleted);
285 break;
286
287 case EVENT_SEND_ENVELOPE_DONE:
288 ar = (AsyncResult) msg.obj;
289 request = (MainThreadRequest) ar.userObj;
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700290 if (ar.exception == null && ar.result != null) {
291 request.result = ar.result;
Derek Tan4d5e5c12014-02-04 11:54:58 -0800292 } else {
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700293 request.result = new IccIoResult(0x6F, 0, (byte[])null);
294 if (ar.result == null) {
295 loge("sendEnvelopeWithStatus: Empty response");
296 } else if (ar.exception instanceof CommandException) {
297 loge("sendEnvelopeWithStatus: CommandException: " +
298 ar.exception);
299 } else {
300 loge("sendEnvelopeWithStatus: exception:" + ar.exception);
301 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800302 }
303 synchronized (request) {
304 request.notifyAll();
305 }
306 break;
307
Shishir Agrawal566b7612013-10-28 14:41:00 -0700308 case CMD_OPEN_CHANNEL:
309 request = (MainThreadRequest) msg.obj;
310 onCompleted = obtainMessage(EVENT_OPEN_CHANNEL_DONE, request);
311 UiccController.getInstance().getUiccCard().iccOpenLogicalChannel(
312 (String)request.argument, onCompleted);
313 break;
314
315 case EVENT_OPEN_CHANNEL_DONE:
316 ar = (AsyncResult) msg.obj;
317 request = (MainThreadRequest) ar.userObj;
318 if (ar.exception == null && ar.result != null) {
Jake Hambye994d462014-02-03 13:10:13 -0800319 request.result = ((int[]) ar.result)[0];
Shishir Agrawal566b7612013-10-28 14:41:00 -0700320 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800321 request.result = -1;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700322 if (ar.result == null) {
323 loge("iccOpenLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800324 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700325 loge("iccOpenLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800326 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700327 } else {
328 loge("iccOpenLogicalChannel: Unknown exception");
329 }
330 }
331 synchronized (request) {
332 request.notifyAll();
333 }
334 break;
335
336 case CMD_CLOSE_CHANNEL:
337 request = (MainThreadRequest) msg.obj;
338 onCompleted = obtainMessage(EVENT_CLOSE_CHANNEL_DONE,
339 request);
340 UiccController.getInstance().getUiccCard().iccCloseLogicalChannel(
Jake Hambye994d462014-02-03 13:10:13 -0800341 (Integer) request.argument,
Shishir Agrawal566b7612013-10-28 14:41:00 -0700342 onCompleted);
343 break;
344
345 case EVENT_CLOSE_CHANNEL_DONE:
Jake Hambye994d462014-02-03 13:10:13 -0800346 handleNullReturnEvent(msg, "iccCloseLogicalChannel");
347 break;
348
349 case CMD_NV_READ_ITEM:
350 request = (MainThreadRequest) msg.obj;
351 onCompleted = obtainMessage(EVENT_NV_READ_ITEM_DONE, request);
352 mPhone.nvReadItem((Integer) request.argument, onCompleted);
353 break;
354
355 case EVENT_NV_READ_ITEM_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700356 ar = (AsyncResult) msg.obj;
357 request = (MainThreadRequest) ar.userObj;
Jake Hambye994d462014-02-03 13:10:13 -0800358 if (ar.exception == null && ar.result != null) {
359 request.result = ar.result; // String
Shishir Agrawal566b7612013-10-28 14:41:00 -0700360 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800361 request.result = "";
362 if (ar.result == null) {
363 loge("nvReadItem: Empty response");
364 } else if (ar.exception instanceof CommandException) {
365 loge("nvReadItem: CommandException: " +
366 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700367 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800368 loge("nvReadItem: Unknown exception");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700369 }
370 }
371 synchronized (request) {
372 request.notifyAll();
373 }
374 break;
375
Jake Hambye994d462014-02-03 13:10:13 -0800376 case CMD_NV_WRITE_ITEM:
377 request = (MainThreadRequest) msg.obj;
378 onCompleted = obtainMessage(EVENT_NV_WRITE_ITEM_DONE, request);
379 Pair<Integer, String> idValue = (Pair<Integer, String>) request.argument;
380 mPhone.nvWriteItem(idValue.first, idValue.second, onCompleted);
381 break;
382
383 case EVENT_NV_WRITE_ITEM_DONE:
384 handleNullReturnEvent(msg, "nvWriteItem");
385 break;
386
387 case CMD_NV_WRITE_CDMA_PRL:
388 request = (MainThreadRequest) msg.obj;
389 onCompleted = obtainMessage(EVENT_NV_WRITE_CDMA_PRL_DONE, request);
390 mPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
391 break;
392
393 case EVENT_NV_WRITE_CDMA_PRL_DONE:
394 handleNullReturnEvent(msg, "nvWriteCdmaPrl");
395 break;
396
397 case CMD_NV_RESET_CONFIG:
398 request = (MainThreadRequest) msg.obj;
399 onCompleted = obtainMessage(EVENT_NV_RESET_CONFIG_DONE, request);
400 mPhone.nvResetConfig((Integer) request.argument, onCompleted);
401 break;
402
403 case EVENT_NV_RESET_CONFIG_DONE:
404 handleNullReturnEvent(msg, "nvResetConfig");
405 break;
406
Jake Hamby7c27be32014-03-03 13:25:59 -0800407 case CMD_GET_PREFERRED_NETWORK_TYPE:
408 request = (MainThreadRequest) msg.obj;
409 onCompleted = obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE_DONE, request);
410 mPhone.getPreferredNetworkType(onCompleted);
411 break;
412
413 case EVENT_GET_PREFERRED_NETWORK_TYPE_DONE:
414 ar = (AsyncResult) msg.obj;
415 request = (MainThreadRequest) ar.userObj;
416 if (ar.exception == null && ar.result != null) {
417 request.result = ar.result; // Integer
418 } else {
419 request.result = -1;
420 if (ar.result == null) {
421 loge("getPreferredNetworkType: Empty response");
422 } else if (ar.exception instanceof CommandException) {
423 loge("getPreferredNetworkType: CommandException: " +
424 ar.exception);
425 } else {
426 loge("getPreferredNetworkType: Unknown exception");
427 }
428 }
429 synchronized (request) {
430 request.notifyAll();
431 }
432 break;
433
434 case CMD_SET_PREFERRED_NETWORK_TYPE:
435 request = (MainThreadRequest) msg.obj;
436 onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);
437 int networkType = (Integer) request.argument;
438 mPhone.setPreferredNetworkType(networkType, onCompleted);
439 break;
440
441 case EVENT_SET_PREFERRED_NETWORK_TYPE_DONE:
442 handleNullReturnEvent(msg, "setPreferredNetworkType");
443 break;
444
Junda Liu787bc7e2014-06-30 13:38:02 -0700445 case CMD_SET_CDMA_SUBSCRIPTION:
446 request = (MainThreadRequest) msg.obj;
447 onCompleted = obtainMessage(EVENT_SET_CDMA_SUBSCRIPTION_DONE, request);
448 int subscriptionType = (Integer) request.argument;
449 mPhone.setCdmaSubscription(subscriptionType, onCompleted);
450 break;
451
452 case EVENT_SET_CDMA_SUBSCRIPTION_DONE:
453 handleNullReturnEvent(msg, "setCdmaSubscription");
454 break;
455
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700456 default:
457 Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
458 break;
459 }
460 }
Jake Hambye994d462014-02-03 13:10:13 -0800461
462 private void handleNullReturnEvent(Message msg, String command) {
463 AsyncResult ar = (AsyncResult) msg.obj;
464 MainThreadRequest request = (MainThreadRequest) ar.userObj;
465 if (ar.exception == null) {
466 request.result = true;
467 } else {
468 request.result = false;
469 if (ar.exception instanceof CommandException) {
470 loge(command + ": CommandException: " + ar.exception);
471 } else {
472 loge(command + ": Unknown exception");
473 }
474 }
475 synchronized (request) {
476 request.notifyAll();
477 }
478 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700479 }
480
481 /**
482 * Posts the specified command to be executed on the main thread,
483 * waits for the request to complete, and returns the result.
484 * @see #sendRequestAsync
485 */
486 private Object sendRequest(int command, Object argument) {
Santos Cordon500b0e02014-06-17 10:33:33 -0700487 return sendRequest(command, argument, null);
Wink Saville36469e72014-06-11 15:17:00 -0700488 }
489
490 /**
491 * Posts the specified command to be executed on the main thread,
492 * waits for the request to complete, and returns the result.
493 * @see #sendRequestAsync
494 */
495 private Object sendRequest(int command, Object argument, Object argument2) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700496 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
497 throw new RuntimeException("This method will deadlock if called from the main thread.");
498 }
499
500 MainThreadRequest request = new MainThreadRequest(argument);
501 Message msg = mMainThreadHandler.obtainMessage(command, request);
502 msg.sendToTarget();
503
504 // Wait for the request to complete
505 synchronized (request) {
506 while (request.result == null) {
507 try {
508 request.wait();
509 } catch (InterruptedException e) {
510 // Do nothing, go back and wait until the request is complete
511 }
512 }
513 }
514 return request.result;
515 }
516
517 /**
518 * Asynchronous ("fire and forget") version of sendRequest():
519 * Posts the specified command to be executed on the main thread, and
520 * returns immediately.
521 * @see #sendRequest
522 */
523 private void sendRequestAsync(int command) {
524 mMainThreadHandler.sendEmptyMessage(command);
525 }
526
527 /**
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -0700528 * Same as {@link #sendRequestAsync(int)} except it takes an argument.
529 * @see {@link #sendRequest(int,Object)}
530 */
531 private void sendRequestAsync(int command, Object argument) {
532 MainThreadRequest request = new MainThreadRequest(argument);
533 Message msg = mMainThreadHandler.obtainMessage(command, request);
534 msg.sendToTarget();
535 }
536
537 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700538 * Initialize the singleton PhoneInterfaceManager instance.
539 * This is only done once, at startup, from PhoneApp.onCreate().
540 */
Santos Cordon406c0342013-08-28 00:07:47 -0700541 /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone,
Santos Cordon117fee72014-05-16 17:56:12 -0700542 CallHandlerServiceProxy callHandlerService) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700543 synchronized (PhoneInterfaceManager.class) {
544 if (sInstance == null) {
Santos Cordon117fee72014-05-16 17:56:12 -0700545 sInstance = new PhoneInterfaceManager(app, phone, callHandlerService);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700546 } else {
547 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
548 }
549 return sInstance;
550 }
551 }
552
553 /** Private constructor; @see init() */
Santos Cordon406c0342013-08-28 00:07:47 -0700554 private PhoneInterfaceManager(PhoneGlobals app, Phone phone,
Santos Cordon117fee72014-05-16 17:56:12 -0700555 CallHandlerServiceProxy callHandlerService) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700556 mApp = app;
557 mPhone = phone;
558 mCM = PhoneGlobals.getInstance().mCM;
559 mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
560 mMainThreadHandler = new MainThreadHandler();
Santos Cordon406c0342013-08-28 00:07:47 -0700561 mCallHandlerService = callHandlerService;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700562 publish();
563 }
564
565 private void publish() {
566 if (DBG) log("publish: " + this);
567
568 ServiceManager.addService("phone", this);
569 }
570
Wink Saville36469e72014-06-11 15:17:00 -0700571 // returns phone associated with the subId.
572 // getPhone(0) returns default phone in single SIM mode.
573 private Phone getPhone(long subId) {
574 // FIXME: hack for the moment
575 return mPhone;
576 // return PhoneUtils.getPhoneUsingSubId(subId);
577 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700578 //
579 // Implementation of the ITelephony interface.
580 //
581
582 public void dial(String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700583 dialUsingSubId(getPreferredVoiceSubscription(), number);
584 }
585
586 public void dialUsingSubId(long subId, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700587 if (DBG) log("dial: " + number);
588 // No permission check needed here: This is just a wrapper around the
589 // ACTION_DIAL intent, which is available to any app since it puts up
590 // the UI before it does anything.
591
592 String url = createTelUrl(number);
593 if (url == null) {
594 return;
595 }
596
597 // PENDING: should we just silently fail if phone is offhook or ringing?
Wink Saville36469e72014-06-11 15:17:00 -0700598 PhoneConstants.State state = mCM.getState(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700599 if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
600 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
601 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Wink Saville36469e72014-06-11 15:17:00 -0700602 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700603 mApp.startActivity(intent);
604 }
605 }
606
607 public void call(String callingPackage, String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700608 callUsingSubId(getPreferredVoiceSubscription(), callingPackage, number);
609 }
610
611 public void callUsingSubId(long subId, String callingPackage, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700612 if (DBG) log("call: " + number);
613
614 // This is just a wrapper around the ACTION_CALL intent, but we still
615 // need to do a permission check since we're calling startActivity()
616 // from the context of the phone app.
617 enforceCallPermission();
618
619 if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
620 != AppOpsManager.MODE_ALLOWED) {
621 return;
622 }
623
624 String url = createTelUrl(number);
625 if (url == null) {
626 return;
627 }
628
629 Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
Wink Saville36469e72014-06-11 15:17:00 -0700630 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700631 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
632 mApp.startActivity(intent);
633 }
634
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700635 /**
636 * End a call based on call state
637 * @return true is a call was ended
638 */
639 public boolean endCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700640 return endCallUsingSubId(getDefaultSubscription());
641 }
642
643 /**
644 * End a call based on the call state of the subId
645 * @return true is a call was ended
646 */
647 public boolean endCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700648 enforceCallPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700649 return (Boolean) sendRequest(CMD_END_CALL, subId, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700650 }
651
652 public void answerRingingCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700653 answerRingingCallUsingSubId(getDefaultSubscription());
654 }
655
656 public void answerRingingCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700657 if (DBG) log("answerRingingCall...");
658 // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
659 // but that can probably wait till the big TelephonyManager API overhaul.
660 // For now, protect this call with the MODIFY_PHONE_STATE permission.
661 enforceModifyPermission();
662 sendRequestAsync(CMD_ANSWER_RINGING_CALL);
663 }
664
665 /**
666 * Make the actual telephony calls to implement answerRingingCall().
667 * This should only be called from the main thread of the Phone app.
668 * @see #answerRingingCall
669 *
670 * TODO: it would be nice to return true if we answered the call, or
671 * false if there wasn't actually a ringing incoming call, or some
672 * other error occurred. (In other words, pass back the return value
673 * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
674 * But that would require calling this method via sendRequest() rather
675 * than sendRequestAsync(), and right now we don't actually *need* that
676 * return value, so let's just return void for now.
677 */
678 private void answerRingingCallInternal() {
679 final boolean hasRingingCall = !mPhone.getRingingCall().isIdle();
680 if (hasRingingCall) {
681 final boolean hasActiveCall = !mPhone.getForegroundCall().isIdle();
682 final boolean hasHoldingCall = !mPhone.getBackgroundCall().isIdle();
683 if (hasActiveCall && hasHoldingCall) {
684 // Both lines are in use!
685 // TODO: provide a flag to let the caller specify what
686 // policy to use if both lines are in use. (The current
687 // behavior is hardwired to "answer incoming, end ongoing",
688 // which is how the CALL button is specced to behave.)
689 PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
690 return;
691 } else {
692 // answerCall() will automatically hold the current active
693 // call, if there is one.
694 PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
695 return;
696 }
697 } else {
698 // No call was ringing.
699 return;
700 }
701 }
702
703 public void silenceRinger() {
704 if (DBG) log("silenceRinger...");
705 // TODO: find a more appropriate permission to check here.
706 // (That can probably wait till the big TelephonyManager API overhaul.
707 // For now, protect this call with the MODIFY_PHONE_STATE permission.)
708 enforceModifyPermission();
709 sendRequestAsync(CMD_SILENCE_RINGER);
710 }
711
712 /**
713 * Internal implemenation of silenceRinger().
714 * This should only be called from the main thread of the Phone app.
715 * @see #silenceRinger
716 */
717 private void silenceRingerInternal() {
718 if ((mCM.getState() == PhoneConstants.State.RINGING)
719 && mApp.notifier.isRinging()) {
720 // Ringer is actually playing, so silence it.
721 if (DBG) log("silenceRingerInternal: silencing...");
722 mApp.notifier.silenceRinger();
723 }
724 }
725
726 public boolean isOffhook() {
Wink Saville36469e72014-06-11 15:17:00 -0700727 return isOffhookUsingSubId(getDefaultSubscription());
728 }
729
730 public boolean isOffhookUsingSubId(long subId) {
731 return (getPhone(subId).getState() == PhoneConstants.State.OFFHOOK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700732 }
733
734 public boolean isRinging() {
Wink Saville36469e72014-06-11 15:17:00 -0700735 return (isRingingUsingSubId(getDefaultSubscription()));
736 }
737
738 public boolean isRingingUsingSubId(long subId) {
739 return (getPhone(subId).getState() == PhoneConstants.State.RINGING);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700740 }
741
742 public boolean isIdle() {
Wink Saville36469e72014-06-11 15:17:00 -0700743 return isIdleUsingSubId(getDefaultSubscription());
744 }
745
746 public boolean isIdleUsingSubId(long subId) {
747 return (getPhone(subId).getState() == PhoneConstants.State.IDLE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700748 }
749
750 public boolean isSimPinEnabled() {
751 enforceReadPermission();
752 return (PhoneGlobals.getInstance().isSimPinEnabled());
753 }
754
755 public boolean supplyPin(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700756 return supplyPinUsingSubId(getDefaultSubscription(), pin);
757 }
758
759 public boolean supplyPinUsingSubId(long subId, String pin) {
760 int [] resultArray = supplyPinReportResultUsingSubId(subId, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700761 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
762 }
763
764 public boolean supplyPuk(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700765 return supplyPukUsingSubId(getDefaultSubscription(), puk, pin);
766 }
767
768 public boolean supplyPukUsingSubId(long subId, String puk, String pin) {
769 int [] resultArray = supplyPukReportResultUsingSubId(subId, puk, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700770 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
771 }
772
773 /** {@hide} */
774 public int[] supplyPinReportResult(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700775 return supplyPinReportResultUsingSubId(getDefaultSubscription(), pin);
776 }
777
778 public int[] supplyPinReportResultUsingSubId(long subId, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700779 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700780 final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700781 checkSimPin.start();
782 return checkSimPin.unlockSim(null, pin);
783 }
784
Wink Saville9de0f752013-10-22 19:04:03 -0700785 /** {@hide} */
786 public int[] supplyPukReportResult(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700787 return supplyPukReportResultUsingSubId(getDefaultSubscription(), puk, pin);
788 }
789
790 public int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700791 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700792 final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700793 checkSimPuk.start();
794 return checkSimPuk.unlockSim(puk, pin);
795 }
796
797 /**
Wink Saville9de0f752013-10-22 19:04:03 -0700798 * Helper thread to turn async call to SimCard#supplyPin into
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700799 * a synchronous one.
800 */
801 private static class UnlockSim extends Thread {
802
803 private final IccCard mSimCard;
804
805 private boolean mDone = false;
Wink Saville9de0f752013-10-22 19:04:03 -0700806 private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
807 private int mRetryCount = -1;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700808
809 // For replies from SimCard interface
810 private Handler mHandler;
811
812 // For async handler to identify request type
813 private static final int SUPPLY_PIN_COMPLETE = 100;
814
815 public UnlockSim(IccCard simCard) {
816 mSimCard = simCard;
817 }
818
819 @Override
820 public void run() {
821 Looper.prepare();
822 synchronized (UnlockSim.this) {
823 mHandler = new Handler() {
824 @Override
825 public void handleMessage(Message msg) {
826 AsyncResult ar = (AsyncResult) msg.obj;
827 switch (msg.what) {
828 case SUPPLY_PIN_COMPLETE:
829 Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
830 synchronized (UnlockSim.this) {
Wink Saville9de0f752013-10-22 19:04:03 -0700831 mRetryCount = msg.arg1;
832 if (ar.exception != null) {
833 if (ar.exception instanceof CommandException &&
834 ((CommandException)(ar.exception)).getCommandError()
835 == CommandException.Error.PASSWORD_INCORRECT) {
836 mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
837 } else {
838 mResult = PhoneConstants.PIN_GENERAL_FAILURE;
839 }
840 } else {
841 mResult = PhoneConstants.PIN_RESULT_SUCCESS;
842 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700843 mDone = true;
844 UnlockSim.this.notifyAll();
845 }
846 break;
847 }
848 }
849 };
850 UnlockSim.this.notifyAll();
851 }
852 Looper.loop();
853 }
854
855 /*
856 * Use PIN or PUK to unlock SIM card
857 *
858 * If PUK is null, unlock SIM card with PIN
859 *
860 * If PUK is not null, unlock SIM card with PUK and set PIN code
861 */
Wink Saville9de0f752013-10-22 19:04:03 -0700862 synchronized int[] unlockSim(String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700863
864 while (mHandler == null) {
865 try {
866 wait();
867 } catch (InterruptedException e) {
868 Thread.currentThread().interrupt();
869 }
870 }
871 Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
872
873 if (puk == null) {
874 mSimCard.supplyPin(pin, callback);
875 } else {
876 mSimCard.supplyPuk(puk, pin, callback);
877 }
878
879 while (!mDone) {
880 try {
881 Log.d(LOG_TAG, "wait for done");
882 wait();
883 } catch (InterruptedException e) {
884 // Restore the interrupted status
885 Thread.currentThread().interrupt();
886 }
887 }
888 Log.d(LOG_TAG, "done");
Wink Saville9de0f752013-10-22 19:04:03 -0700889 int[] resultArray = new int[2];
890 resultArray[0] = mResult;
891 resultArray[1] = mRetryCount;
892 return resultArray;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700893 }
894 }
895
896 public void updateServiceLocation() {
Wink Saville36469e72014-06-11 15:17:00 -0700897 updateServiceLocationUsingSubId(getDefaultSubscription());
898
899 }
900
901 public void updateServiceLocationUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700902 // No permission check needed here: this call is harmless, and it's
903 // needed for the ServiceState.requestStateUpdate() call (which is
904 // already intentionally exposed to 3rd parties.)
Wink Saville36469e72014-06-11 15:17:00 -0700905 getPhone(subId).updateServiceLocation();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700906 }
907
908 public boolean isRadioOn() {
Wink Saville36469e72014-06-11 15:17:00 -0700909 return isRadioOnUsingSubId(getDefaultSubscription());
910 }
911
912 public boolean isRadioOnUsingSubId(long subId) {
913 return getPhone(subId).getServiceState().getState() != ServiceState.STATE_POWER_OFF;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700914 }
915
916 public void toggleRadioOnOff() {
Wink Saville36469e72014-06-11 15:17:00 -0700917 toggleRadioOnOffUsingSubId(getDefaultSubscription());
918
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700919 }
Wink Saville36469e72014-06-11 15:17:00 -0700920
921 public void toggleRadioOnOffUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700922 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700923 getPhone(subId).setRadioPower(!isRadioOnUsingSubId(subId));
924 }
925
926 public boolean setRadio(boolean turnOn) {
927 return setRadioUsingSubId(getDefaultSubscription(), turnOn);
928 }
929
930 public boolean setRadioUsingSubId(long subId, boolean turnOn) {
931 enforceModifyPermission();
932 if ((getPhone(subId).getServiceState().getState() !=
933 ServiceState.STATE_POWER_OFF) != turnOn) {
934 toggleRadioOnOffUsingSubId(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700935 }
936 return true;
937 }
Wink Saville36469e72014-06-11 15:17:00 -0700938
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700939 public boolean setRadioPower(boolean turnOn) {
Wink Saville36469e72014-06-11 15:17:00 -0700940 return setRadioPowerUsingSubId(getDefaultSubscription(), turnOn);
941 }
942
943 public boolean setRadioPowerUsingSubId(long subId, boolean turnOn) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700944 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700945 getPhone(subId).setRadioPower(turnOn);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700946 return true;
947 }
948
Wink Saville36469e72014-06-11 15:17:00 -0700949 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700950 public boolean enableDataConnectivity() {
951 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700952 long subId = SubscriptionManager.getDefaultDataSubId();
953 getPhone(subId).setDataEnabled(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700954 return true;
955 }
956
Wink Saville36469e72014-06-11 15:17:00 -0700957 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700958 public boolean disableDataConnectivity() {
959 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700960 long subId = SubscriptionManager.getDefaultDataSubId();
961 getPhone(subId).setDataEnabled(false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700962 return true;
963 }
964
Wink Saville36469e72014-06-11 15:17:00 -0700965 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700966 public boolean isDataConnectivityPossible() {
Wink Saville36469e72014-06-11 15:17:00 -0700967 long subId = SubscriptionManager.getDefaultDataSubId();
968 return getPhone(subId).isDataConnectivityPossible();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700969 }
970
971 public boolean handlePinMmi(String dialString) {
Wink Saville36469e72014-06-11 15:17:00 -0700972 return handlePinMmiUsingSubId(getDefaultSubscription(), dialString);
973 }
974
975 public boolean handlePinMmiUsingSubId(long subId, String dialString) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700976 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700977 return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700978 }
979
980 public void cancelMissedCallsNotification() {
Wink Saville36469e72014-06-11 15:17:00 -0700981 cancelMissedCallsNotificationUsingSubId(getDefaultSubscription());
982 }
983
984 public void cancelMissedCallsNotificationUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700985 enforceModifyPermission();
986 mApp.notificationMgr.cancelMissedCallNotification();
987 }
988
989 public int getCallState() {
Wink Saville36469e72014-06-11 15:17:00 -0700990 return getCallStateUsingSubId(getDefaultSubscription());
991 }
992
993 public int getCallStateUsingSubId(long subId) {
994 return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700995 }
996
997 public int getDataState() {
Wink Saville36469e72014-06-11 15:17:00 -0700998 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
999 return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001000 }
1001
1002 public int getDataActivity() {
Wink Saville36469e72014-06-11 15:17:00 -07001003 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1004 return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001005 }
1006
1007 @Override
1008 public Bundle getCellLocation() {
1009 try {
1010 mApp.enforceCallingOrSelfPermission(
1011 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1012 } catch (SecurityException e) {
1013 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1014 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1015 // is the weaker precondition
1016 mApp.enforceCallingOrSelfPermission(
1017 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1018 }
1019
Jake Hambye994d462014-02-03 13:10:13 -08001020 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001021 if (DBG_LOC) log("getCellLocation: is active user");
1022 Bundle data = new Bundle();
1023 mPhone.getCellLocation().fillInNotifierBundle(data);
1024 return data;
1025 } else {
1026 if (DBG_LOC) log("getCellLocation: suppress non-active user");
1027 return null;
1028 }
1029 }
1030
1031 @Override
1032 public void enableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001033 enableLocationUpdatesUsingSubId(getDefaultSubscription());
1034 }
1035
1036 public void enableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001037 mApp.enforceCallingOrSelfPermission(
1038 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001039 getPhone(subId).enableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001040 }
1041
1042 @Override
1043 public void disableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001044 disableLocationUpdatesUsingSubId(getDefaultSubscription());
1045 }
1046
1047 public void disableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001048 mApp.enforceCallingOrSelfPermission(
1049 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001050 getPhone(subId).disableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001051 }
1052
1053 @Override
1054 @SuppressWarnings("unchecked")
1055 public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1056 try {
1057 mApp.enforceCallingOrSelfPermission(
1058 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1059 } catch (SecurityException e) {
1060 // If we have ACCESS_FINE_LOCATION permission, skip the check
1061 // for ACCESS_COARSE_LOCATION
1062 // A failure should throw the SecurityException from
1063 // ACCESS_COARSE_LOCATION since this is the weaker precondition
1064 mApp.enforceCallingOrSelfPermission(
1065 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1066 }
1067
1068 if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1069 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1070 return null;
1071 }
Jake Hambye994d462014-02-03 13:10:13 -08001072 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001073 if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1074
1075 ArrayList<NeighboringCellInfo> cells = null;
1076
1077 try {
1078 cells = (ArrayList<NeighboringCellInfo>) sendRequest(
Wink Saville36469e72014-06-11 15:17:00 -07001079 CMD_HANDLE_NEIGHBORING_CELL, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001080 } catch (RuntimeException e) {
Wink Saville36469e72014-06-11 15:17:00 -07001081 Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001082 }
1083 return cells;
1084 } else {
1085 if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1086 return null;
1087 }
1088 }
1089
1090
1091 @Override
1092 public List<CellInfo> getAllCellInfo() {
1093 try {
1094 mApp.enforceCallingOrSelfPermission(
1095 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1096 } catch (SecurityException e) {
1097 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1098 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1099 // is the weaker precondition
1100 mApp.enforceCallingOrSelfPermission(
1101 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1102 }
1103
Jake Hambye994d462014-02-03 13:10:13 -08001104 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001105 if (DBG_LOC) log("getAllCellInfo: is active user");
1106 return mPhone.getAllCellInfo();
1107 } else {
1108 if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1109 return null;
1110 }
1111 }
1112
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -07001113 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001114 public void setCellInfoListRate(int rateInMillis) {
1115 mPhone.setCellInfoListRate(rateInMillis);
1116 }
1117
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001118 //
1119 // Internal helper methods.
1120 //
1121
Jake Hambye994d462014-02-03 13:10:13 -08001122 private static boolean checkIfCallerIsSelfOrForegroundUser() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001123 boolean ok;
1124
1125 boolean self = Binder.getCallingUid() == Process.myUid();
1126 if (!self) {
1127 // Get the caller's user id then clear the calling identity
1128 // which will be restored in the finally clause.
1129 int callingUser = UserHandle.getCallingUserId();
1130 long ident = Binder.clearCallingIdentity();
1131
1132 try {
1133 // With calling identity cleared the current user is the foreground user.
1134 int foregroundUser = ActivityManager.getCurrentUser();
1135 ok = (foregroundUser == callingUser);
1136 if (DBG_LOC) {
1137 log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1138 + " callingUser=" + callingUser + " ok=" + ok);
1139 }
1140 } catch (Exception ex) {
1141 if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1142 ok = false;
1143 } finally {
1144 Binder.restoreCallingIdentity(ident);
1145 }
1146 } else {
1147 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1148 ok = true;
1149 }
1150 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1151 return ok;
1152 }
1153
1154 /**
1155 * Make sure the caller has the READ_PHONE_STATE permission.
1156 *
1157 * @throws SecurityException if the caller does not have the required permission
1158 */
1159 private void enforceReadPermission() {
1160 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
1161 }
1162
1163 /**
1164 * Make sure the caller has the MODIFY_PHONE_STATE permission.
1165 *
1166 * @throws SecurityException if the caller does not have the required permission
1167 */
1168 private void enforceModifyPermission() {
1169 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1170 }
1171
1172 /**
1173 * Make sure the caller has the CALL_PHONE permission.
1174 *
1175 * @throws SecurityException if the caller does not have the required permission
1176 */
1177 private void enforceCallPermission() {
1178 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1179 }
1180
Shishir Agrawal566b7612013-10-28 14:41:00 -07001181 /**
Gabriel Peal36ebb0d2014-03-20 09:20:43 -07001182 * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1183 *
1184 * @throws SecurityException if the caller does not have the required permission
1185 */
1186 private void enforcePrivilegedPhoneStatePermission() {
1187 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1188 null);
1189 }
1190
1191 /**
Shishir Agrawal566b7612013-10-28 14:41:00 -07001192 * Make sure the caller has SIM_COMMUNICATION permission.
1193 *
1194 * @throws SecurityException if the caller does not have the required permission.
1195 */
1196 private void enforceSimCommunicationPermission() {
1197 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.SIM_COMMUNICATION, null);
1198 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001199
1200 private String createTelUrl(String number) {
1201 if (TextUtils.isEmpty(number)) {
1202 return null;
1203 }
1204
Jake Hambye994d462014-02-03 13:10:13 -08001205 return "tel:" + number;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001206 }
1207
Ihab Awadf9e92732013-12-05 18:02:52 -08001208 private static void log(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001209 Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1210 }
1211
Ihab Awadf9e92732013-12-05 18:02:52 -08001212 private static void loge(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001213 Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1214 }
1215
1216 public int getActivePhoneType() {
Wink Saville36469e72014-06-11 15:17:00 -07001217 return getActivePhoneTypeUsingSubId(getDefaultSubscription());
1218 }
1219
1220 public int getActivePhoneTypeUsingSubId(long subId) {
1221 return getPhone(subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001222 }
1223
1224 /**
1225 * Returns the CDMA ERI icon index to display
1226 */
1227 public int getCdmaEriIconIndex() {
Wink Saville36469e72014-06-11 15:17:00 -07001228 return getCdmaEriIconIndexUsingSubId(getDefaultSubscription());
1229
1230 }
1231
1232 public int getCdmaEriIconIndexUsingSubId(long subId) {
1233 return getPhone(subId).getCdmaEriIconIndex();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001234 }
1235
1236 /**
1237 * Returns the CDMA ERI icon mode,
1238 * 0 - ON
1239 * 1 - FLASHING
1240 */
1241 public int getCdmaEriIconMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001242 return getCdmaEriIconModeUsingSubId(getDefaultSubscription());
1243 }
1244
1245 public int getCdmaEriIconModeUsingSubId(long subId) {
1246 return getPhone(subId).getCdmaEriIconMode();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001247 }
1248
1249 /**
1250 * Returns the CDMA ERI text,
1251 */
1252 public String getCdmaEriText() {
Wink Saville36469e72014-06-11 15:17:00 -07001253 return getCdmaEriTextUsingSubId(getDefaultSubscription());
1254 }
1255
1256 public String getCdmaEriTextUsingSubId(long subId) {
1257 return getPhone(subId).getCdmaEriText();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001258 }
1259
1260 /**
1261 * Returns true if CDMA provisioning needs to run.
1262 */
1263 public boolean needsOtaServiceProvisioning() {
1264 return mPhone.needsOtaServiceProvisioning();
1265 }
1266
1267 /**
1268 * Returns the unread count of voicemails
1269 */
1270 public int getVoiceMessageCount() {
Wink Saville36469e72014-06-11 15:17:00 -07001271 return getVoiceMessageCountUsingSubId(getDefaultSubscription());
1272 }
1273
1274 /**
1275 * Returns the unread count of voicemails for a subId
1276 */
1277 public int getVoiceMessageCountUsingSubId( long subId) {
1278 return getPhone(subId).getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001279 }
1280
1281 /**
1282 * Returns the data network type
1283 *
1284 * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1285 */
1286 @Override
1287 public int getNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001288 return getNetworkTypeUsingSubId(getDefaultSubscription());
1289 }
1290
1291 /**
1292 * Returns the network type for a subId
1293 */
1294 @Override
1295 public int getNetworkTypeUsingSubId(long subId) {
1296 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001297 }
1298
1299 /**
1300 * Returns the data network type
1301 */
1302 @Override
1303 public int getDataNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001304 return getDataNetworkTypeUsingSubId(getDefaultSubscription());
1305 }
1306
1307 /**
1308 * Returns the data network type for a subId
1309 */
1310 @Override
1311 public int getDataNetworkTypeUsingSubId(long subId) {
1312 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001313 }
1314
1315 /**
1316 * Returns the data network type
1317 */
1318 @Override
1319 public int getVoiceNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001320 return getVoiceNetworkTypeUsingSubId(getDefaultSubscription());
1321 }
1322
1323 /**
1324 * Returns the Voice network type for a subId
1325 */
1326 @Override
1327 public int getVoiceNetworkTypeUsingSubId(long subId) {
1328 return getPhone(subId).getServiceState().getVoiceNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001329 }
1330
1331 /**
1332 * @return true if a ICC card is present
1333 */
1334 public boolean hasIccCard() {
Wink Saville36469e72014-06-11 15:17:00 -07001335 // FIXME Make changes to pass defaultSimId of type int
1336 return hasIccCardUsingSlotId(getDefaultSubscription());
1337 }
1338
1339 /**
1340 * @return true if a ICC card is present for a slotId
1341 */
1342 public boolean hasIccCardUsingSlotId(long slotId) {
1343 return getPhone(slotId).getIccCard().hasIccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001344 }
1345
1346 /**
1347 * Return if the current radio is LTE on CDMA. This
1348 * is a tri-state return value as for a period of time
1349 * the mode may be unknown.
1350 *
1351 * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
Jake Hambye994d462014-02-03 13:10:13 -08001352 * or {@link Phone#LTE_ON_CDMA_TRUE}
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001353 */
1354 public int getLteOnCdmaMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001355 return getLteOnCdmaModeUsingSubId(getDefaultSubscription());
1356 }
1357
1358 public int getLteOnCdmaModeUsingSubId(long subId) {
1359 return getPhone(subId).getLteOnCdmaMode();
1360 }
1361
1362 public void setPhone(Phone phone) {
1363 mPhone = phone;
1364 }
1365
1366 /**
1367 * {@hide}
1368 * Returns Default subId, 0 in the case of single standby.
1369 */
1370 private long getDefaultSubscription() {
1371 return SubscriptionManager.getDefaultSubId();
1372 }
1373
1374 private long getPreferredVoiceSubscription() {
1375 return SubscriptionManager.getDefaultVoiceSubId();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001376 }
Ihab Awadf2177b72013-11-25 13:33:23 -08001377
1378 /**
1379 * @see android.telephony.TelephonyManager.WifiCallingChoices
1380 */
1381 public int getWhenToMakeWifiCalls() {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001382 return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1383 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
Ihab Awadf2177b72013-11-25 13:33:23 -08001384 }
1385
1386 /**
1387 * @see android.telephony.TelephonyManager.WifiCallingChoices
1388 */
1389 public void setWhenToMakeWifiCalls(int preference) {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001390 if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1391 Settings.System.putInt(mPhone.getContext().getContentResolver(),
1392 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
Ihab Awadf9e92732013-12-05 18:02:52 -08001393 }
1394
Sailesh Nepald1e68152013-12-12 19:08:02 -08001395 private static int getWhenToMakeWifiCallsDefaultPreference() {
1396 // TODO(sail): Use a build property to choose this value.
Evan Charlton9829e882013-12-19 15:30:38 -08001397 return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
Ihab Awadf2177b72013-11-25 13:33:23 -08001398 }
Shishir Agrawal69f68122013-12-16 17:25:49 -08001399
Shishir Agrawal566b7612013-10-28 14:41:00 -07001400 @Override
1401 public int iccOpenLogicalChannel(String AID) {
1402 enforceSimCommunicationPermission();
1403
1404 if (DBG) log("iccOpenLogicalChannel: " + AID);
1405 Integer channel = (Integer)sendRequest(CMD_OPEN_CHANNEL, AID);
1406 if (DBG) log("iccOpenLogicalChannel: " + channel);
Jake Hambye994d462014-02-03 13:10:13 -08001407 return channel;
Shishir Agrawal566b7612013-10-28 14:41:00 -07001408 }
1409
1410 @Override
1411 public boolean iccCloseLogicalChannel(int channel) {
1412 enforceSimCommunicationPermission();
1413
1414 if (DBG) log("iccCloseLogicalChannel: " + channel);
1415 if (channel < 0) {
1416 return false;
1417 }
Jake Hambye994d462014-02-03 13:10:13 -08001418 Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
Shishir Agrawal566b7612013-10-28 14:41:00 -07001419 if (DBG) log("iccCloseLogicalChannel: " + success);
1420 return success;
1421 }
1422
1423 @Override
1424 public String iccTransmitApduLogicalChannel(int channel, int cla,
1425 int command, int p1, int p2, int p3, String data) {
1426 enforceSimCommunicationPermission();
1427
1428 if (DBG) {
1429 log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1430 " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1431 " data=" + data);
1432 }
1433
1434 if (channel < 0) {
1435 return "";
1436 }
1437
1438 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU,
1439 new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1440 if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1441
1442 // If the payload is null, there was an error. Indicate that by returning
1443 // an empty string.
1444 if (response.payload == null) {
1445 return "";
1446 }
1447
1448 // Append the returned status code to the end of the response payload.
1449 String s = Integer.toHexString(
1450 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1451 s = IccUtils.bytesToHexString(response.payload) + s;
1452 return s;
1453 }
Jake Hambye994d462014-02-03 13:10:13 -08001454
Evan Charltonc66da362014-05-16 14:06:40 -07001455 @Override
1456 public String sendEnvelopeWithStatus(String content) {
1457 enforceSimCommunicationPermission();
1458
1459 IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
1460 if (response.payload == null) {
1461 return "";
1462 }
1463
1464 // Append the returned status code to the end of the response payload.
1465 String s = Integer.toHexString(
1466 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1467 s = IccUtils.bytesToHexString(response.payload) + s;
1468 return s;
1469 }
1470
Jake Hambye994d462014-02-03 13:10:13 -08001471 /**
1472 * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1473 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1474 *
1475 * @param itemID the ID of the item to read
1476 * @return the NV item as a String, or null on error.
1477 */
1478 @Override
1479 public String nvReadItem(int itemID) {
1480 enforceModifyPermission();
1481 if (DBG) log("nvReadItem: item " + itemID);
1482 String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
1483 if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
1484 return value;
1485 }
1486
1487 /**
1488 * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1489 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1490 *
1491 * @param itemID the ID of the item to read
1492 * @param itemValue the value to write, as a String
1493 * @return true on success; false on any failure
1494 */
1495 @Override
1496 public boolean nvWriteItem(int itemID, String itemValue) {
1497 enforceModifyPermission();
1498 if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
1499 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
1500 new Pair<Integer, String>(itemID, itemValue));
1501 if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
1502 return success;
1503 }
1504
1505 /**
1506 * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
1507 * Used for device configuration by some CDMA operators.
1508 *
1509 * @param preferredRoamingList byte array containing the new PRL
1510 * @return true on success; false on any failure
1511 */
1512 @Override
1513 public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
1514 enforceModifyPermission();
1515 if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
1516 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
1517 if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
1518 return success;
1519 }
1520
1521 /**
1522 * Perform the specified type of NV config reset.
1523 * Used for device configuration by some CDMA operators.
1524 *
1525 * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
1526 * @return true on success; false on any failure
1527 */
1528 @Override
1529 public boolean nvResetConfig(int resetType) {
1530 enforceModifyPermission();
1531 if (DBG) log("nvResetConfig: type " + resetType);
1532 Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
1533 if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
1534 return success;
1535 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001536
1537 /**
Wink Saville36469e72014-06-11 15:17:00 -07001538 * {@hide}
1539 * Returns Default sim, 0 in the case of single standby.
1540 */
1541 public int getDefaultSim() {
1542 //TODO Need to get it from Telephony Devcontroller
1543 return 0;
1544 }
1545
1546 public String[] getPcscfAddress() {
1547 enforceReadPermission();
1548 return mPhone.getPcscfAddress();
1549 }
1550
1551 public void setImsRegistrationState(boolean registered) {
1552 enforceModifyPermission();
1553 mPhone.setImsRegistrationState(registered);
1554 }
1555
1556 /**
Jake Hamby7c27be32014-03-03 13:25:59 -08001557 * Get the preferred network type.
1558 * Used for device configuration by some CDMA operators.
1559 *
1560 * @return the preferred network type, defined in RILConstants.java.
1561 */
1562 @Override
1563 public int getPreferredNetworkType() {
1564 enforceModifyPermission();
1565 if (DBG) log("getPreferredNetworkType");
1566 int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null);
1567 int networkType = (result != null ? result[0] : -1);
1568 if (DBG) log("getPreferredNetworkType: " + networkType);
1569 return networkType;
1570 }
1571
1572 /**
1573 * Set the preferred network type.
1574 * Used for device configuration by some CDMA operators.
1575 *
1576 * @param networkType the preferred network type, defined in RILConstants.java.
1577 * @return true on success; false on any failure.
1578 */
1579 @Override
1580 public boolean setPreferredNetworkType(int networkType) {
1581 enforceModifyPermission();
1582 if (DBG) log("setPreferredNetworkType: type " + networkType);
1583 Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType);
1584 if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
1585 return success;
1586 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001587
1588 /**
Junda Liu787bc7e2014-06-30 13:38:02 -07001589 * Set the CDMA subscription source.
1590 * Used for device supporting both NV and RUIM for CDMA.
1591 *
1592 * @param subscriptionType the subscription type, 0 for RUIM, 1 for NV.
1593 * @return true on success; false on any failure.
1594 */
1595 @Override
1596 public boolean setCdmaSubscription(int subscriptionType) {
1597 enforceModifyPermission();
1598 if (DBG) log("setCdmaSubscription: type " + subscriptionType);
1599 if (subscriptionType != mPhone.CDMA_SUBSCRIPTION_RUIM_SIM &&
1600 subscriptionType != mPhone.CDMA_SUBSCRIPTION_NV) {
1601 loge("setCdmaSubscription: unsupported subscriptionType.");
1602 return false;
1603 }
1604 Boolean success = (Boolean) sendRequest(CMD_SET_CDMA_SUBSCRIPTION, subscriptionType);
1605 if (DBG) log("setCdmaSubscription: " + (success ? "ok" : "fail"));
1606 if (success) {
1607 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1608 Settings.Global.CDMA_SUBSCRIPTION_MODE, subscriptionType);
1609 }
1610 return success;
1611 }
1612
1613 /**
Robert Greenwalted86e582014-05-21 20:03:20 -07001614 * Set mobile data enabled
1615 * Used by the user through settings etc to turn on/off mobile data
1616 *
1617 * @param enable {@code true} turn turn data on, else {@code false}
1618 */
1619 @Override
1620 public void setDataEnabled(boolean enable) {
1621 enforceModifyPermission();
1622 mPhone.setDataEnabled(enable);
1623 }
1624
1625 /**
Robert Greenwalt646120a2014-05-23 11:54:03 -07001626 * Get whether mobile data is enabled.
1627 *
1628 * Note that this used to be available from ConnectivityService, gated by
1629 * ACCESS_NETWORK_STATE permission, so this will accept either that or
1630 * our MODIFY_PHONE_STATE.
Robert Greenwalted86e582014-05-21 20:03:20 -07001631 *
1632 * @return {@code true} if data is enabled else {@code false}
1633 */
1634 @Override
1635 public boolean getDataEnabled() {
Robert Greenwalt646120a2014-05-23 11:54:03 -07001636 try {
1637 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
1638 null);
1639 } catch (Exception e) {
1640 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
1641 null);
1642 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001643 return mPhone.getDataEnabled();
1644 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001645}