blob: c90d833ad00e3d5761878c26687b7612ea26b9bc [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;
119
120 /**
Shishir Agrawal566b7612013-10-28 14:41:00 -0700121 * A request object to use for transmitting data to an ICC.
122 */
123 private static final class IccAPDUArgument {
124 public int channel, cla, command, p1, p2, p3;
125 public String data;
126
127 public IccAPDUArgument(int channel, int cla, int command,
128 int p1, int p2, int p3, String data) {
129 this.channel = channel;
130 this.cla = cla;
131 this.command = command;
132 this.p1 = p1;
133 this.p2 = p2;
134 this.p3 = p3;
135 this.data = data;
136 }
137 }
138
139 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700140 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
141 * request after sending. The main thread will notify the request when it is complete.
142 */
143 private static final class MainThreadRequest {
144 /** The argument to use for the request */
145 public Object argument;
146 /** The result of the request that is run on the main thread */
147 public Object result;
148
149 public MainThreadRequest(Object argument) {
150 this.argument = argument;
151 }
152 }
153
Sailesh Nepalcc0375f2013-11-13 09:15:18 -0800154 private static final class IncomingThirdPartyCallArgs {
155 public final ComponentName component;
156 public final String callId;
157 public final String callerDisplayName;
158
159 public IncomingThirdPartyCallArgs(ComponentName component, String callId,
160 String callerDisplayName) {
161 this.component = component;
162 this.callId = callId;
163 this.callerDisplayName = callerDisplayName;
164 }
165 }
166
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700167 /**
168 * A handler that processes messages on the main thread in the phone process. Since many
169 * of the Phone calls are not thread safe this is needed to shuttle the requests from the
170 * inbound binder threads to the main thread in the phone process. The Binder thread
171 * may provide a {@link MainThreadRequest} object in the msg.obj field that they are waiting
172 * on, which will be notified when the operation completes and will contain the result of the
173 * request.
174 *
175 * <p>If a MainThreadRequest object is provided in the msg.obj field,
176 * note that request.result must be set to something non-null for the calling thread to
177 * unblock.
178 */
179 private final class MainThreadHandler extends Handler {
180 @Override
181 public void handleMessage(Message msg) {
182 MainThreadRequest request;
183 Message onCompleted;
184 AsyncResult ar;
185
186 switch (msg.what) {
187 case CMD_HANDLE_PIN_MMI:
188 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800189 request.result = mPhone.handlePinMmi((String) request.argument);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700190 // Wake up the requesting thread
191 synchronized (request) {
192 request.notifyAll();
193 }
194 break;
195
196 case CMD_HANDLE_NEIGHBORING_CELL:
197 request = (MainThreadRequest) msg.obj;
198 onCompleted = obtainMessage(EVENT_NEIGHBORING_CELL_DONE,
199 request);
200 mPhone.getNeighboringCids(onCompleted);
201 break;
202
203 case EVENT_NEIGHBORING_CELL_DONE:
204 ar = (AsyncResult) msg.obj;
205 request = (MainThreadRequest) ar.userObj;
206 if (ar.exception == null && ar.result != null) {
207 request.result = ar.result;
208 } else {
209 // create an empty list to notify the waiting thread
Jake Hambye994d462014-02-03 13:10:13 -0800210 request.result = new ArrayList<NeighboringCellInfo>(0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700211 }
212 // Wake up the requesting thread
213 synchronized (request) {
214 request.notifyAll();
215 }
216 break;
217
218 case CMD_ANSWER_RINGING_CALL:
219 answerRingingCallInternal();
220 break;
221
222 case CMD_SILENCE_RINGER:
223 silenceRingerInternal();
224 break;
225
226 case CMD_END_CALL:
227 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800228 boolean hungUp;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700229 int phoneType = mPhone.getPhoneType();
230 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
231 // CDMA: If the user presses the Power button we treat it as
232 // ending the complete call session
233 hungUp = PhoneUtils.hangupRingingAndActive(mPhone);
234 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
235 // GSM: End the call as per the Phone state
236 hungUp = PhoneUtils.hangup(mCM);
237 } else {
238 throw new IllegalStateException("Unexpected phone type: " + phoneType);
239 }
240 if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up"));
241 request.result = hungUp;
242 // Wake up the requesting thread
243 synchronized (request) {
244 request.notifyAll();
245 }
246 break;
247
Shishir Agrawal566b7612013-10-28 14:41:00 -0700248 case CMD_TRANSMIT_APDU:
249 request = (MainThreadRequest) msg.obj;
250 IccAPDUArgument argument = (IccAPDUArgument) request.argument;
251 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_DONE, request);
252 UiccController.getInstance().getUiccCard().iccTransmitApduLogicalChannel(
253 argument.channel, argument.cla, argument.command,
254 argument.p1, argument.p2, argument.p3, argument.data,
255 onCompleted);
256 break;
257
258 case EVENT_TRANSMIT_APDU_DONE:
259 ar = (AsyncResult) msg.obj;
260 request = (MainThreadRequest) ar.userObj;
261 if (ar.exception == null && ar.result != null) {
262 request.result = ar.result;
263 } else {
264 request.result = new IccIoResult(0x6F, 0, (byte[])null);
265 if (ar.result == null) {
266 loge("iccTransmitApduLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800267 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700268 loge("iccTransmitApduLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800269 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700270 } else {
271 loge("iccTransmitApduLogicalChannel: Unknown exception");
272 }
273 }
274 synchronized (request) {
275 request.notifyAll();
276 }
277 break;
278
Derek Tan4d5e5c12014-02-04 11:54:58 -0800279 case CMD_SEND_ENVELOPE:
280 request = (MainThreadRequest) msg.obj;
281 onCompleted = obtainMessage(EVENT_SEND_ENVELOPE_DONE, request);
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700282 UiccController.getInstance().getUiccCard().sendEnvelopeWithStatus(
Derek Tan4d5e5c12014-02-04 11:54:58 -0800283 (String)request.argument, onCompleted);
284 break;
285
286 case EVENT_SEND_ENVELOPE_DONE:
287 ar = (AsyncResult) msg.obj;
288 request = (MainThreadRequest) ar.userObj;
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700289 if (ar.exception == null && ar.result != null) {
290 request.result = ar.result;
Derek Tan4d5e5c12014-02-04 11:54:58 -0800291 } else {
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700292 request.result = new IccIoResult(0x6F, 0, (byte[])null);
293 if (ar.result == null) {
294 loge("sendEnvelopeWithStatus: Empty response");
295 } else if (ar.exception instanceof CommandException) {
296 loge("sendEnvelopeWithStatus: CommandException: " +
297 ar.exception);
298 } else {
299 loge("sendEnvelopeWithStatus: exception:" + ar.exception);
300 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800301 }
302 synchronized (request) {
303 request.notifyAll();
304 }
305 break;
306
Shishir Agrawal566b7612013-10-28 14:41:00 -0700307 case CMD_OPEN_CHANNEL:
308 request = (MainThreadRequest) msg.obj;
309 onCompleted = obtainMessage(EVENT_OPEN_CHANNEL_DONE, request);
310 UiccController.getInstance().getUiccCard().iccOpenLogicalChannel(
311 (String)request.argument, onCompleted);
312 break;
313
314 case EVENT_OPEN_CHANNEL_DONE:
315 ar = (AsyncResult) msg.obj;
316 request = (MainThreadRequest) ar.userObj;
317 if (ar.exception == null && ar.result != null) {
Jake Hambye994d462014-02-03 13:10:13 -0800318 request.result = ((int[]) ar.result)[0];
Shishir Agrawal566b7612013-10-28 14:41:00 -0700319 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800320 request.result = -1;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700321 if (ar.result == null) {
322 loge("iccOpenLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800323 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700324 loge("iccOpenLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800325 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700326 } else {
327 loge("iccOpenLogicalChannel: Unknown exception");
328 }
329 }
330 synchronized (request) {
331 request.notifyAll();
332 }
333 break;
334
335 case CMD_CLOSE_CHANNEL:
336 request = (MainThreadRequest) msg.obj;
337 onCompleted = obtainMessage(EVENT_CLOSE_CHANNEL_DONE,
338 request);
339 UiccController.getInstance().getUiccCard().iccCloseLogicalChannel(
Jake Hambye994d462014-02-03 13:10:13 -0800340 (Integer) request.argument,
Shishir Agrawal566b7612013-10-28 14:41:00 -0700341 onCompleted);
342 break;
343
344 case EVENT_CLOSE_CHANNEL_DONE:
Jake Hambye994d462014-02-03 13:10:13 -0800345 handleNullReturnEvent(msg, "iccCloseLogicalChannel");
346 break;
347
348 case CMD_NV_READ_ITEM:
349 request = (MainThreadRequest) msg.obj;
350 onCompleted = obtainMessage(EVENT_NV_READ_ITEM_DONE, request);
351 mPhone.nvReadItem((Integer) request.argument, onCompleted);
352 break;
353
354 case EVENT_NV_READ_ITEM_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700355 ar = (AsyncResult) msg.obj;
356 request = (MainThreadRequest) ar.userObj;
Jake Hambye994d462014-02-03 13:10:13 -0800357 if (ar.exception == null && ar.result != null) {
358 request.result = ar.result; // String
Shishir Agrawal566b7612013-10-28 14:41:00 -0700359 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800360 request.result = "";
361 if (ar.result == null) {
362 loge("nvReadItem: Empty response");
363 } else if (ar.exception instanceof CommandException) {
364 loge("nvReadItem: CommandException: " +
365 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700366 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800367 loge("nvReadItem: Unknown exception");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700368 }
369 }
370 synchronized (request) {
371 request.notifyAll();
372 }
373 break;
374
Jake Hambye994d462014-02-03 13:10:13 -0800375 case CMD_NV_WRITE_ITEM:
376 request = (MainThreadRequest) msg.obj;
377 onCompleted = obtainMessage(EVENT_NV_WRITE_ITEM_DONE, request);
378 Pair<Integer, String> idValue = (Pair<Integer, String>) request.argument;
379 mPhone.nvWriteItem(idValue.first, idValue.second, onCompleted);
380 break;
381
382 case EVENT_NV_WRITE_ITEM_DONE:
383 handleNullReturnEvent(msg, "nvWriteItem");
384 break;
385
386 case CMD_NV_WRITE_CDMA_PRL:
387 request = (MainThreadRequest) msg.obj;
388 onCompleted = obtainMessage(EVENT_NV_WRITE_CDMA_PRL_DONE, request);
389 mPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
390 break;
391
392 case EVENT_NV_WRITE_CDMA_PRL_DONE:
393 handleNullReturnEvent(msg, "nvWriteCdmaPrl");
394 break;
395
396 case CMD_NV_RESET_CONFIG:
397 request = (MainThreadRequest) msg.obj;
398 onCompleted = obtainMessage(EVENT_NV_RESET_CONFIG_DONE, request);
399 mPhone.nvResetConfig((Integer) request.argument, onCompleted);
400 break;
401
402 case EVENT_NV_RESET_CONFIG_DONE:
403 handleNullReturnEvent(msg, "nvResetConfig");
404 break;
405
Jake Hamby7c27be32014-03-03 13:25:59 -0800406 case CMD_GET_PREFERRED_NETWORK_TYPE:
407 request = (MainThreadRequest) msg.obj;
408 onCompleted = obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE_DONE, request);
409 mPhone.getPreferredNetworkType(onCompleted);
410 break;
411
412 case EVENT_GET_PREFERRED_NETWORK_TYPE_DONE:
413 ar = (AsyncResult) msg.obj;
414 request = (MainThreadRequest) ar.userObj;
415 if (ar.exception == null && ar.result != null) {
416 request.result = ar.result; // Integer
417 } else {
418 request.result = -1;
419 if (ar.result == null) {
420 loge("getPreferredNetworkType: Empty response");
421 } else if (ar.exception instanceof CommandException) {
422 loge("getPreferredNetworkType: CommandException: " +
423 ar.exception);
424 } else {
425 loge("getPreferredNetworkType: Unknown exception");
426 }
427 }
428 synchronized (request) {
429 request.notifyAll();
430 }
431 break;
432
433 case CMD_SET_PREFERRED_NETWORK_TYPE:
434 request = (MainThreadRequest) msg.obj;
435 onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);
436 int networkType = (Integer) request.argument;
437 mPhone.setPreferredNetworkType(networkType, onCompleted);
438 break;
439
440 case EVENT_SET_PREFERRED_NETWORK_TYPE_DONE:
441 handleNullReturnEvent(msg, "setPreferredNetworkType");
442 break;
443
Junda Liu787bc7e2014-06-30 13:38:02 -0700444 case CMD_SET_CDMA_SUBSCRIPTION:
445 request = (MainThreadRequest) msg.obj;
446 onCompleted = obtainMessage(EVENT_SET_CDMA_SUBSCRIPTION_DONE, request);
447 int subscriptionType = (Integer) request.argument;
448 mPhone.setCdmaSubscription(subscriptionType, onCompleted);
449 break;
450
451 case EVENT_SET_CDMA_SUBSCRIPTION_DONE:
452 handleNullReturnEvent(msg, "setCdmaSubscription");
453 break;
454
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700455 default:
456 Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
457 break;
458 }
459 }
Jake Hambye994d462014-02-03 13:10:13 -0800460
461 private void handleNullReturnEvent(Message msg, String command) {
462 AsyncResult ar = (AsyncResult) msg.obj;
463 MainThreadRequest request = (MainThreadRequest) ar.userObj;
464 if (ar.exception == null) {
465 request.result = true;
466 } else {
467 request.result = false;
468 if (ar.exception instanceof CommandException) {
469 loge(command + ": CommandException: " + ar.exception);
470 } else {
471 loge(command + ": Unknown exception");
472 }
473 }
474 synchronized (request) {
475 request.notifyAll();
476 }
477 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700478 }
479
480 /**
481 * Posts the specified command to be executed on the main thread,
482 * waits for the request to complete, and returns the result.
483 * @see #sendRequestAsync
484 */
485 private Object sendRequest(int command, Object argument) {
Santos Cordon500b0e02014-06-17 10:33:33 -0700486 return sendRequest(command, argument, null);
Wink Saville36469e72014-06-11 15:17:00 -0700487 }
488
489 /**
490 * Posts the specified command to be executed on the main thread,
491 * waits for the request to complete, and returns the result.
492 * @see #sendRequestAsync
493 */
494 private Object sendRequest(int command, Object argument, Object argument2) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700495 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
496 throw new RuntimeException("This method will deadlock if called from the main thread.");
497 }
498
499 MainThreadRequest request = new MainThreadRequest(argument);
500 Message msg = mMainThreadHandler.obtainMessage(command, request);
501 msg.sendToTarget();
502
503 // Wait for the request to complete
504 synchronized (request) {
505 while (request.result == null) {
506 try {
507 request.wait();
508 } catch (InterruptedException e) {
509 // Do nothing, go back and wait until the request is complete
510 }
511 }
512 }
513 return request.result;
514 }
515
516 /**
517 * Asynchronous ("fire and forget") version of sendRequest():
518 * Posts the specified command to be executed on the main thread, and
519 * returns immediately.
520 * @see #sendRequest
521 */
522 private void sendRequestAsync(int command) {
523 mMainThreadHandler.sendEmptyMessage(command);
524 }
525
526 /**
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -0700527 * Same as {@link #sendRequestAsync(int)} except it takes an argument.
528 * @see {@link #sendRequest(int,Object)}
529 */
530 private void sendRequestAsync(int command, Object argument) {
531 MainThreadRequest request = new MainThreadRequest(argument);
532 Message msg = mMainThreadHandler.obtainMessage(command, request);
533 msg.sendToTarget();
534 }
535
536 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700537 * Initialize the singleton PhoneInterfaceManager instance.
538 * This is only done once, at startup, from PhoneApp.onCreate().
539 */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700540 /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700541 synchronized (PhoneInterfaceManager.class) {
542 if (sInstance == null) {
Sailesh Nepal194161e2014-07-03 08:57:44 -0700543 sInstance = new PhoneInterfaceManager(app, phone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700544 } else {
545 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
546 }
547 return sInstance;
548 }
549 }
550
551 /** Private constructor; @see init() */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700552 private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700553 mApp = app;
554 mPhone = phone;
555 mCM = PhoneGlobals.getInstance().mCM;
556 mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
557 mMainThreadHandler = new MainThreadHandler();
558 publish();
559 }
560
561 private void publish() {
562 if (DBG) log("publish: " + this);
563
564 ServiceManager.addService("phone", this);
565 }
566
Wink Saville36469e72014-06-11 15:17:00 -0700567 // returns phone associated with the subId.
568 // getPhone(0) returns default phone in single SIM mode.
569 private Phone getPhone(long subId) {
570 // FIXME: hack for the moment
571 return mPhone;
572 // return PhoneUtils.getPhoneUsingSubId(subId);
573 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700574 //
575 // Implementation of the ITelephony interface.
576 //
577
578 public void dial(String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700579 dialUsingSubId(getPreferredVoiceSubscription(), number);
580 }
581
582 public void dialUsingSubId(long subId, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700583 if (DBG) log("dial: " + number);
584 // No permission check needed here: This is just a wrapper around the
585 // ACTION_DIAL intent, which is available to any app since it puts up
586 // the UI before it does anything.
587
588 String url = createTelUrl(number);
589 if (url == null) {
590 return;
591 }
592
593 // PENDING: should we just silently fail if phone is offhook or ringing?
Wink Saville36469e72014-06-11 15:17:00 -0700594 PhoneConstants.State state = mCM.getState(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700595 if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
596 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
597 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Wink Saville36469e72014-06-11 15:17:00 -0700598 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700599 mApp.startActivity(intent);
600 }
601 }
602
603 public void call(String callingPackage, String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700604 callUsingSubId(getPreferredVoiceSubscription(), callingPackage, number);
605 }
606
607 public void callUsingSubId(long subId, String callingPackage, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700608 if (DBG) log("call: " + number);
609
610 // This is just a wrapper around the ACTION_CALL intent, but we still
611 // need to do a permission check since we're calling startActivity()
612 // from the context of the phone app.
613 enforceCallPermission();
614
615 if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
616 != AppOpsManager.MODE_ALLOWED) {
617 return;
618 }
619
620 String url = createTelUrl(number);
621 if (url == null) {
622 return;
623 }
624
625 Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
Wink Saville36469e72014-06-11 15:17:00 -0700626 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700627 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
628 mApp.startActivity(intent);
629 }
630
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700631 /**
632 * End a call based on call state
633 * @return true is a call was ended
634 */
635 public boolean endCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700636 return endCallUsingSubId(getDefaultSubscription());
637 }
638
639 /**
640 * End a call based on the call state of the subId
641 * @return true is a call was ended
642 */
643 public boolean endCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700644 enforceCallPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700645 return (Boolean) sendRequest(CMD_END_CALL, subId, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700646 }
647
648 public void answerRingingCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700649 answerRingingCallUsingSubId(getDefaultSubscription());
650 }
651
652 public void answerRingingCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700653 if (DBG) log("answerRingingCall...");
654 // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
655 // but that can probably wait till the big TelephonyManager API overhaul.
656 // For now, protect this call with the MODIFY_PHONE_STATE permission.
657 enforceModifyPermission();
658 sendRequestAsync(CMD_ANSWER_RINGING_CALL);
659 }
660
661 /**
662 * Make the actual telephony calls to implement answerRingingCall().
663 * This should only be called from the main thread of the Phone app.
664 * @see #answerRingingCall
665 *
666 * TODO: it would be nice to return true if we answered the call, or
667 * false if there wasn't actually a ringing incoming call, or some
668 * other error occurred. (In other words, pass back the return value
669 * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
670 * But that would require calling this method via sendRequest() rather
671 * than sendRequestAsync(), and right now we don't actually *need* that
672 * return value, so let's just return void for now.
673 */
674 private void answerRingingCallInternal() {
675 final boolean hasRingingCall = !mPhone.getRingingCall().isIdle();
676 if (hasRingingCall) {
677 final boolean hasActiveCall = !mPhone.getForegroundCall().isIdle();
678 final boolean hasHoldingCall = !mPhone.getBackgroundCall().isIdle();
679 if (hasActiveCall && hasHoldingCall) {
680 // Both lines are in use!
681 // TODO: provide a flag to let the caller specify what
682 // policy to use if both lines are in use. (The current
683 // behavior is hardwired to "answer incoming, end ongoing",
684 // which is how the CALL button is specced to behave.)
685 PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
686 return;
687 } else {
688 // answerCall() will automatically hold the current active
689 // call, if there is one.
690 PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
691 return;
692 }
693 } else {
694 // No call was ringing.
695 return;
696 }
697 }
698
699 public void silenceRinger() {
700 if (DBG) log("silenceRinger...");
701 // TODO: find a more appropriate permission to check here.
702 // (That can probably wait till the big TelephonyManager API overhaul.
703 // For now, protect this call with the MODIFY_PHONE_STATE permission.)
704 enforceModifyPermission();
705 sendRequestAsync(CMD_SILENCE_RINGER);
706 }
707
708 /**
709 * Internal implemenation of silenceRinger().
710 * This should only be called from the main thread of the Phone app.
711 * @see #silenceRinger
712 */
713 private void silenceRingerInternal() {
714 if ((mCM.getState() == PhoneConstants.State.RINGING)
715 && mApp.notifier.isRinging()) {
716 // Ringer is actually playing, so silence it.
717 if (DBG) log("silenceRingerInternal: silencing...");
718 mApp.notifier.silenceRinger();
719 }
720 }
721
722 public boolean isOffhook() {
Wink Saville36469e72014-06-11 15:17:00 -0700723 return isOffhookUsingSubId(getDefaultSubscription());
724 }
725
726 public boolean isOffhookUsingSubId(long subId) {
727 return (getPhone(subId).getState() == PhoneConstants.State.OFFHOOK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700728 }
729
730 public boolean isRinging() {
Wink Saville36469e72014-06-11 15:17:00 -0700731 return (isRingingUsingSubId(getDefaultSubscription()));
732 }
733
734 public boolean isRingingUsingSubId(long subId) {
735 return (getPhone(subId).getState() == PhoneConstants.State.RINGING);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700736 }
737
738 public boolean isIdle() {
Wink Saville36469e72014-06-11 15:17:00 -0700739 return isIdleUsingSubId(getDefaultSubscription());
740 }
741
742 public boolean isIdleUsingSubId(long subId) {
743 return (getPhone(subId).getState() == PhoneConstants.State.IDLE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700744 }
745
746 public boolean isSimPinEnabled() {
747 enforceReadPermission();
748 return (PhoneGlobals.getInstance().isSimPinEnabled());
749 }
750
751 public boolean supplyPin(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700752 return supplyPinUsingSubId(getDefaultSubscription(), pin);
753 }
754
755 public boolean supplyPinUsingSubId(long subId, String pin) {
756 int [] resultArray = supplyPinReportResultUsingSubId(subId, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700757 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
758 }
759
760 public boolean supplyPuk(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700761 return supplyPukUsingSubId(getDefaultSubscription(), puk, pin);
762 }
763
764 public boolean supplyPukUsingSubId(long subId, String puk, String pin) {
765 int [] resultArray = supplyPukReportResultUsingSubId(subId, puk, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700766 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
767 }
768
769 /** {@hide} */
770 public int[] supplyPinReportResult(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700771 return supplyPinReportResultUsingSubId(getDefaultSubscription(), pin);
772 }
773
774 public int[] supplyPinReportResultUsingSubId(long subId, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700775 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700776 final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700777 checkSimPin.start();
778 return checkSimPin.unlockSim(null, pin);
779 }
780
Wink Saville9de0f752013-10-22 19:04:03 -0700781 /** {@hide} */
782 public int[] supplyPukReportResult(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700783 return supplyPukReportResultUsingSubId(getDefaultSubscription(), puk, pin);
784 }
785
786 public int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700787 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700788 final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700789 checkSimPuk.start();
790 return checkSimPuk.unlockSim(puk, pin);
791 }
792
793 /**
Wink Saville9de0f752013-10-22 19:04:03 -0700794 * Helper thread to turn async call to SimCard#supplyPin into
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700795 * a synchronous one.
796 */
797 private static class UnlockSim extends Thread {
798
799 private final IccCard mSimCard;
800
801 private boolean mDone = false;
Wink Saville9de0f752013-10-22 19:04:03 -0700802 private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
803 private int mRetryCount = -1;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700804
805 // For replies from SimCard interface
806 private Handler mHandler;
807
808 // For async handler to identify request type
809 private static final int SUPPLY_PIN_COMPLETE = 100;
810
811 public UnlockSim(IccCard simCard) {
812 mSimCard = simCard;
813 }
814
815 @Override
816 public void run() {
817 Looper.prepare();
818 synchronized (UnlockSim.this) {
819 mHandler = new Handler() {
820 @Override
821 public void handleMessage(Message msg) {
822 AsyncResult ar = (AsyncResult) msg.obj;
823 switch (msg.what) {
824 case SUPPLY_PIN_COMPLETE:
825 Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
826 synchronized (UnlockSim.this) {
Wink Saville9de0f752013-10-22 19:04:03 -0700827 mRetryCount = msg.arg1;
828 if (ar.exception != null) {
829 if (ar.exception instanceof CommandException &&
830 ((CommandException)(ar.exception)).getCommandError()
831 == CommandException.Error.PASSWORD_INCORRECT) {
832 mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
833 } else {
834 mResult = PhoneConstants.PIN_GENERAL_FAILURE;
835 }
836 } else {
837 mResult = PhoneConstants.PIN_RESULT_SUCCESS;
838 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700839 mDone = true;
840 UnlockSim.this.notifyAll();
841 }
842 break;
843 }
844 }
845 };
846 UnlockSim.this.notifyAll();
847 }
848 Looper.loop();
849 }
850
851 /*
852 * Use PIN or PUK to unlock SIM card
853 *
854 * If PUK is null, unlock SIM card with PIN
855 *
856 * If PUK is not null, unlock SIM card with PUK and set PIN code
857 */
Wink Saville9de0f752013-10-22 19:04:03 -0700858 synchronized int[] unlockSim(String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700859
860 while (mHandler == null) {
861 try {
862 wait();
863 } catch (InterruptedException e) {
864 Thread.currentThread().interrupt();
865 }
866 }
867 Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
868
869 if (puk == null) {
870 mSimCard.supplyPin(pin, callback);
871 } else {
872 mSimCard.supplyPuk(puk, pin, callback);
873 }
874
875 while (!mDone) {
876 try {
877 Log.d(LOG_TAG, "wait for done");
878 wait();
879 } catch (InterruptedException e) {
880 // Restore the interrupted status
881 Thread.currentThread().interrupt();
882 }
883 }
884 Log.d(LOG_TAG, "done");
Wink Saville9de0f752013-10-22 19:04:03 -0700885 int[] resultArray = new int[2];
886 resultArray[0] = mResult;
887 resultArray[1] = mRetryCount;
888 return resultArray;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700889 }
890 }
891
892 public void updateServiceLocation() {
Wink Saville36469e72014-06-11 15:17:00 -0700893 updateServiceLocationUsingSubId(getDefaultSubscription());
894
895 }
896
897 public void updateServiceLocationUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700898 // No permission check needed here: this call is harmless, and it's
899 // needed for the ServiceState.requestStateUpdate() call (which is
900 // already intentionally exposed to 3rd parties.)
Wink Saville36469e72014-06-11 15:17:00 -0700901 getPhone(subId).updateServiceLocation();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700902 }
903
904 public boolean isRadioOn() {
Wink Saville36469e72014-06-11 15:17:00 -0700905 return isRadioOnUsingSubId(getDefaultSubscription());
906 }
907
908 public boolean isRadioOnUsingSubId(long subId) {
909 return getPhone(subId).getServiceState().getState() != ServiceState.STATE_POWER_OFF;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700910 }
911
912 public void toggleRadioOnOff() {
Wink Saville36469e72014-06-11 15:17:00 -0700913 toggleRadioOnOffUsingSubId(getDefaultSubscription());
914
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700915 }
Wink Saville36469e72014-06-11 15:17:00 -0700916
917 public void toggleRadioOnOffUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700918 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700919 getPhone(subId).setRadioPower(!isRadioOnUsingSubId(subId));
920 }
921
922 public boolean setRadio(boolean turnOn) {
923 return setRadioUsingSubId(getDefaultSubscription(), turnOn);
924 }
925
926 public boolean setRadioUsingSubId(long subId, boolean turnOn) {
927 enforceModifyPermission();
928 if ((getPhone(subId).getServiceState().getState() !=
929 ServiceState.STATE_POWER_OFF) != turnOn) {
930 toggleRadioOnOffUsingSubId(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700931 }
932 return true;
933 }
Wink Saville36469e72014-06-11 15:17:00 -0700934
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700935 public boolean setRadioPower(boolean turnOn) {
Wink Saville36469e72014-06-11 15:17:00 -0700936 return setRadioPowerUsingSubId(getDefaultSubscription(), turnOn);
937 }
938
939 public boolean setRadioPowerUsingSubId(long subId, boolean turnOn) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700940 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700941 getPhone(subId).setRadioPower(turnOn);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700942 return true;
943 }
944
Wink Saville36469e72014-06-11 15:17:00 -0700945 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700946 public boolean enableDataConnectivity() {
947 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700948 long subId = SubscriptionManager.getDefaultDataSubId();
949 getPhone(subId).setDataEnabled(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700950 return true;
951 }
952
Wink Saville36469e72014-06-11 15:17:00 -0700953 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700954 public boolean disableDataConnectivity() {
955 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700956 long subId = SubscriptionManager.getDefaultDataSubId();
957 getPhone(subId).setDataEnabled(false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700958 return true;
959 }
960
Wink Saville36469e72014-06-11 15:17:00 -0700961 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700962 public boolean isDataConnectivityPossible() {
Wink Saville36469e72014-06-11 15:17:00 -0700963 long subId = SubscriptionManager.getDefaultDataSubId();
964 return getPhone(subId).isDataConnectivityPossible();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700965 }
966
967 public boolean handlePinMmi(String dialString) {
Wink Saville36469e72014-06-11 15:17:00 -0700968 return handlePinMmiUsingSubId(getDefaultSubscription(), dialString);
969 }
970
971 public boolean handlePinMmiUsingSubId(long subId, String dialString) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700972 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700973 return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700974 }
975
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700976 public int getCallState() {
Wink Saville36469e72014-06-11 15:17:00 -0700977 return getCallStateUsingSubId(getDefaultSubscription());
978 }
979
980 public int getCallStateUsingSubId(long subId) {
981 return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700982 }
983
984 public int getDataState() {
Wink Saville36469e72014-06-11 15:17:00 -0700985 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
986 return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700987 }
988
989 public int getDataActivity() {
Wink Saville36469e72014-06-11 15:17:00 -0700990 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
991 return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700992 }
993
994 @Override
995 public Bundle getCellLocation() {
996 try {
997 mApp.enforceCallingOrSelfPermission(
998 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
999 } catch (SecurityException e) {
1000 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1001 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1002 // is the weaker precondition
1003 mApp.enforceCallingOrSelfPermission(
1004 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1005 }
1006
Jake Hambye994d462014-02-03 13:10:13 -08001007 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001008 if (DBG_LOC) log("getCellLocation: is active user");
1009 Bundle data = new Bundle();
1010 mPhone.getCellLocation().fillInNotifierBundle(data);
1011 return data;
1012 } else {
1013 if (DBG_LOC) log("getCellLocation: suppress non-active user");
1014 return null;
1015 }
1016 }
1017
1018 @Override
1019 public void enableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001020 enableLocationUpdatesUsingSubId(getDefaultSubscription());
1021 }
1022
1023 public void enableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001024 mApp.enforceCallingOrSelfPermission(
1025 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001026 getPhone(subId).enableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001027 }
1028
1029 @Override
1030 public void disableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001031 disableLocationUpdatesUsingSubId(getDefaultSubscription());
1032 }
1033
1034 public void disableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001035 mApp.enforceCallingOrSelfPermission(
1036 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001037 getPhone(subId).disableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001038 }
1039
1040 @Override
1041 @SuppressWarnings("unchecked")
1042 public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1043 try {
1044 mApp.enforceCallingOrSelfPermission(
1045 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1046 } catch (SecurityException e) {
1047 // If we have ACCESS_FINE_LOCATION permission, skip the check
1048 // for ACCESS_COARSE_LOCATION
1049 // A failure should throw the SecurityException from
1050 // ACCESS_COARSE_LOCATION since this is the weaker precondition
1051 mApp.enforceCallingOrSelfPermission(
1052 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1053 }
1054
1055 if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1056 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1057 return null;
1058 }
Jake Hambye994d462014-02-03 13:10:13 -08001059 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001060 if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1061
1062 ArrayList<NeighboringCellInfo> cells = null;
1063
1064 try {
1065 cells = (ArrayList<NeighboringCellInfo>) sendRequest(
Wink Saville36469e72014-06-11 15:17:00 -07001066 CMD_HANDLE_NEIGHBORING_CELL, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001067 } catch (RuntimeException e) {
Wink Saville36469e72014-06-11 15:17:00 -07001068 Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001069 }
1070 return cells;
1071 } else {
1072 if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1073 return null;
1074 }
1075 }
1076
1077
1078 @Override
1079 public List<CellInfo> getAllCellInfo() {
1080 try {
1081 mApp.enforceCallingOrSelfPermission(
1082 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1083 } catch (SecurityException e) {
1084 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1085 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1086 // is the weaker precondition
1087 mApp.enforceCallingOrSelfPermission(
1088 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1089 }
1090
Jake Hambye994d462014-02-03 13:10:13 -08001091 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001092 if (DBG_LOC) log("getAllCellInfo: is active user");
1093 return mPhone.getAllCellInfo();
1094 } else {
1095 if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1096 return null;
1097 }
1098 }
1099
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -07001100 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001101 public void setCellInfoListRate(int rateInMillis) {
1102 mPhone.setCellInfoListRate(rateInMillis);
1103 }
1104
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001105 //
1106 // Internal helper methods.
1107 //
1108
Jake Hambye994d462014-02-03 13:10:13 -08001109 private static boolean checkIfCallerIsSelfOrForegroundUser() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001110 boolean ok;
1111
1112 boolean self = Binder.getCallingUid() == Process.myUid();
1113 if (!self) {
1114 // Get the caller's user id then clear the calling identity
1115 // which will be restored in the finally clause.
1116 int callingUser = UserHandle.getCallingUserId();
1117 long ident = Binder.clearCallingIdentity();
1118
1119 try {
1120 // With calling identity cleared the current user is the foreground user.
1121 int foregroundUser = ActivityManager.getCurrentUser();
1122 ok = (foregroundUser == callingUser);
1123 if (DBG_LOC) {
1124 log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1125 + " callingUser=" + callingUser + " ok=" + ok);
1126 }
1127 } catch (Exception ex) {
1128 if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1129 ok = false;
1130 } finally {
1131 Binder.restoreCallingIdentity(ident);
1132 }
1133 } else {
1134 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1135 ok = true;
1136 }
1137 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1138 return ok;
1139 }
1140
1141 /**
1142 * Make sure the caller has the READ_PHONE_STATE permission.
1143 *
1144 * @throws SecurityException if the caller does not have the required permission
1145 */
1146 private void enforceReadPermission() {
1147 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
1148 }
1149
1150 /**
1151 * Make sure the caller has the MODIFY_PHONE_STATE permission.
1152 *
1153 * @throws SecurityException if the caller does not have the required permission
1154 */
1155 private void enforceModifyPermission() {
1156 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1157 }
1158
1159 /**
1160 * Make sure the caller has the CALL_PHONE permission.
1161 *
1162 * @throws SecurityException if the caller does not have the required permission
1163 */
1164 private void enforceCallPermission() {
1165 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1166 }
1167
Shishir Agrawal566b7612013-10-28 14:41:00 -07001168 /**
Gabriel Peal36ebb0d2014-03-20 09:20:43 -07001169 * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1170 *
1171 * @throws SecurityException if the caller does not have the required permission
1172 */
1173 private void enforcePrivilegedPhoneStatePermission() {
1174 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1175 null);
1176 }
1177
1178 /**
Shishir Agrawal566b7612013-10-28 14:41:00 -07001179 * Make sure the caller has SIM_COMMUNICATION permission.
1180 *
1181 * @throws SecurityException if the caller does not have the required permission.
1182 */
1183 private void enforceSimCommunicationPermission() {
1184 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.SIM_COMMUNICATION, null);
1185 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001186
1187 private String createTelUrl(String number) {
1188 if (TextUtils.isEmpty(number)) {
1189 return null;
1190 }
1191
Jake Hambye994d462014-02-03 13:10:13 -08001192 return "tel:" + number;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001193 }
1194
Ihab Awadf9e92732013-12-05 18:02:52 -08001195 private static void log(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001196 Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1197 }
1198
Ihab Awadf9e92732013-12-05 18:02:52 -08001199 private static void loge(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001200 Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1201 }
1202
1203 public int getActivePhoneType() {
Wink Saville36469e72014-06-11 15:17:00 -07001204 return getActivePhoneTypeUsingSubId(getDefaultSubscription());
1205 }
1206
1207 public int getActivePhoneTypeUsingSubId(long subId) {
1208 return getPhone(subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001209 }
1210
1211 /**
1212 * Returns the CDMA ERI icon index to display
1213 */
1214 public int getCdmaEriIconIndex() {
Wink Saville36469e72014-06-11 15:17:00 -07001215 return getCdmaEriIconIndexUsingSubId(getDefaultSubscription());
1216
1217 }
1218
1219 public int getCdmaEriIconIndexUsingSubId(long subId) {
1220 return getPhone(subId).getCdmaEriIconIndex();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001221 }
1222
1223 /**
1224 * Returns the CDMA ERI icon mode,
1225 * 0 - ON
1226 * 1 - FLASHING
1227 */
1228 public int getCdmaEriIconMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001229 return getCdmaEriIconModeUsingSubId(getDefaultSubscription());
1230 }
1231
1232 public int getCdmaEriIconModeUsingSubId(long subId) {
1233 return getPhone(subId).getCdmaEriIconMode();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001234 }
1235
1236 /**
1237 * Returns the CDMA ERI text,
1238 */
1239 public String getCdmaEriText() {
Wink Saville36469e72014-06-11 15:17:00 -07001240 return getCdmaEriTextUsingSubId(getDefaultSubscription());
1241 }
1242
1243 public String getCdmaEriTextUsingSubId(long subId) {
1244 return getPhone(subId).getCdmaEriText();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001245 }
1246
1247 /**
1248 * Returns true if CDMA provisioning needs to run.
1249 */
1250 public boolean needsOtaServiceProvisioning() {
1251 return mPhone.needsOtaServiceProvisioning();
1252 }
1253
1254 /**
1255 * Returns the unread count of voicemails
1256 */
1257 public int getVoiceMessageCount() {
Wink Saville36469e72014-06-11 15:17:00 -07001258 return getVoiceMessageCountUsingSubId(getDefaultSubscription());
1259 }
1260
1261 /**
1262 * Returns the unread count of voicemails for a subId
1263 */
1264 public int getVoiceMessageCountUsingSubId( long subId) {
1265 return getPhone(subId).getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001266 }
1267
1268 /**
1269 * Returns the data network type
1270 *
1271 * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1272 */
1273 @Override
1274 public int getNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001275 return getNetworkTypeUsingSubId(getDefaultSubscription());
1276 }
1277
1278 /**
1279 * Returns the network type for a subId
1280 */
1281 @Override
1282 public int getNetworkTypeUsingSubId(long subId) {
1283 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001284 }
1285
1286 /**
1287 * Returns the data network type
1288 */
1289 @Override
1290 public int getDataNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001291 return getDataNetworkTypeUsingSubId(getDefaultSubscription());
1292 }
1293
1294 /**
1295 * Returns the data network type for a subId
1296 */
1297 @Override
1298 public int getDataNetworkTypeUsingSubId(long subId) {
1299 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001300 }
1301
1302 /**
1303 * Returns the data network type
1304 */
1305 @Override
1306 public int getVoiceNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001307 return getVoiceNetworkTypeUsingSubId(getDefaultSubscription());
1308 }
1309
1310 /**
1311 * Returns the Voice network type for a subId
1312 */
1313 @Override
1314 public int getVoiceNetworkTypeUsingSubId(long subId) {
1315 return getPhone(subId).getServiceState().getVoiceNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001316 }
1317
1318 /**
1319 * @return true if a ICC card is present
1320 */
1321 public boolean hasIccCard() {
Wink Saville36469e72014-06-11 15:17:00 -07001322 // FIXME Make changes to pass defaultSimId of type int
1323 return hasIccCardUsingSlotId(getDefaultSubscription());
1324 }
1325
1326 /**
1327 * @return true if a ICC card is present for a slotId
1328 */
1329 public boolean hasIccCardUsingSlotId(long slotId) {
1330 return getPhone(slotId).getIccCard().hasIccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001331 }
1332
1333 /**
1334 * Return if the current radio is LTE on CDMA. This
1335 * is a tri-state return value as for a period of time
1336 * the mode may be unknown.
1337 *
1338 * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
Jake Hambye994d462014-02-03 13:10:13 -08001339 * or {@link Phone#LTE_ON_CDMA_TRUE}
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001340 */
1341 public int getLteOnCdmaMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001342 return getLteOnCdmaModeUsingSubId(getDefaultSubscription());
1343 }
1344
1345 public int getLteOnCdmaModeUsingSubId(long subId) {
1346 return getPhone(subId).getLteOnCdmaMode();
1347 }
1348
1349 public void setPhone(Phone phone) {
1350 mPhone = phone;
1351 }
1352
1353 /**
1354 * {@hide}
1355 * Returns Default subId, 0 in the case of single standby.
1356 */
1357 private long getDefaultSubscription() {
1358 return SubscriptionManager.getDefaultSubId();
1359 }
1360
1361 private long getPreferredVoiceSubscription() {
1362 return SubscriptionManager.getDefaultVoiceSubId();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001363 }
Ihab Awadf2177b72013-11-25 13:33:23 -08001364
1365 /**
1366 * @see android.telephony.TelephonyManager.WifiCallingChoices
1367 */
1368 public int getWhenToMakeWifiCalls() {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001369 return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1370 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
Ihab Awadf2177b72013-11-25 13:33:23 -08001371 }
1372
1373 /**
1374 * @see android.telephony.TelephonyManager.WifiCallingChoices
1375 */
1376 public void setWhenToMakeWifiCalls(int preference) {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001377 if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1378 Settings.System.putInt(mPhone.getContext().getContentResolver(),
1379 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
Ihab Awadf9e92732013-12-05 18:02:52 -08001380 }
1381
Sailesh Nepald1e68152013-12-12 19:08:02 -08001382 private static int getWhenToMakeWifiCallsDefaultPreference() {
1383 // TODO(sail): Use a build property to choose this value.
Evan Charlton9829e882013-12-19 15:30:38 -08001384 return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
Ihab Awadf2177b72013-11-25 13:33:23 -08001385 }
Shishir Agrawal69f68122013-12-16 17:25:49 -08001386
Shishir Agrawal566b7612013-10-28 14:41:00 -07001387 @Override
1388 public int iccOpenLogicalChannel(String AID) {
1389 enforceSimCommunicationPermission();
1390
1391 if (DBG) log("iccOpenLogicalChannel: " + AID);
1392 Integer channel = (Integer)sendRequest(CMD_OPEN_CHANNEL, AID);
1393 if (DBG) log("iccOpenLogicalChannel: " + channel);
Jake Hambye994d462014-02-03 13:10:13 -08001394 return channel;
Shishir Agrawal566b7612013-10-28 14:41:00 -07001395 }
1396
1397 @Override
1398 public boolean iccCloseLogicalChannel(int channel) {
1399 enforceSimCommunicationPermission();
1400
1401 if (DBG) log("iccCloseLogicalChannel: " + channel);
1402 if (channel < 0) {
1403 return false;
1404 }
Jake Hambye994d462014-02-03 13:10:13 -08001405 Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
Shishir Agrawal566b7612013-10-28 14:41:00 -07001406 if (DBG) log("iccCloseLogicalChannel: " + success);
1407 return success;
1408 }
1409
1410 @Override
1411 public String iccTransmitApduLogicalChannel(int channel, int cla,
1412 int command, int p1, int p2, int p3, String data) {
1413 enforceSimCommunicationPermission();
1414
1415 if (DBG) {
1416 log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1417 " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1418 " data=" + data);
1419 }
1420
1421 if (channel < 0) {
1422 return "";
1423 }
1424
1425 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU,
1426 new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1427 if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1428
1429 // If the payload is null, there was an error. Indicate that by returning
1430 // an empty string.
1431 if (response.payload == null) {
1432 return "";
1433 }
1434
1435 // Append the returned status code to the end of the response payload.
1436 String s = Integer.toHexString(
1437 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1438 s = IccUtils.bytesToHexString(response.payload) + s;
1439 return s;
1440 }
Jake Hambye994d462014-02-03 13:10:13 -08001441
Evan Charltonc66da362014-05-16 14:06:40 -07001442 @Override
1443 public String sendEnvelopeWithStatus(String content) {
1444 enforceSimCommunicationPermission();
1445
1446 IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
1447 if (response.payload == null) {
1448 return "";
1449 }
1450
1451 // Append the returned status code to the end of the response payload.
1452 String s = Integer.toHexString(
1453 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1454 s = IccUtils.bytesToHexString(response.payload) + s;
1455 return s;
1456 }
1457
Jake Hambye994d462014-02-03 13:10:13 -08001458 /**
1459 * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1460 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1461 *
1462 * @param itemID the ID of the item to read
1463 * @return the NV item as a String, or null on error.
1464 */
1465 @Override
1466 public String nvReadItem(int itemID) {
1467 enforceModifyPermission();
1468 if (DBG) log("nvReadItem: item " + itemID);
1469 String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
1470 if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
1471 return value;
1472 }
1473
1474 /**
1475 * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1476 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1477 *
1478 * @param itemID the ID of the item to read
1479 * @param itemValue the value to write, as a String
1480 * @return true on success; false on any failure
1481 */
1482 @Override
1483 public boolean nvWriteItem(int itemID, String itemValue) {
1484 enforceModifyPermission();
1485 if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
1486 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
1487 new Pair<Integer, String>(itemID, itemValue));
1488 if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
1489 return success;
1490 }
1491
1492 /**
1493 * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
1494 * Used for device configuration by some CDMA operators.
1495 *
1496 * @param preferredRoamingList byte array containing the new PRL
1497 * @return true on success; false on any failure
1498 */
1499 @Override
1500 public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
1501 enforceModifyPermission();
1502 if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
1503 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
1504 if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
1505 return success;
1506 }
1507
1508 /**
1509 * Perform the specified type of NV config reset.
1510 * Used for device configuration by some CDMA operators.
1511 *
1512 * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
1513 * @return true on success; false on any failure
1514 */
1515 @Override
1516 public boolean nvResetConfig(int resetType) {
1517 enforceModifyPermission();
1518 if (DBG) log("nvResetConfig: type " + resetType);
1519 Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
1520 if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
1521 return success;
1522 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001523
1524 /**
Wink Saville36469e72014-06-11 15:17:00 -07001525 * {@hide}
1526 * Returns Default sim, 0 in the case of single standby.
1527 */
1528 public int getDefaultSim() {
1529 //TODO Need to get it from Telephony Devcontroller
1530 return 0;
1531 }
1532
1533 public String[] getPcscfAddress() {
1534 enforceReadPermission();
1535 return mPhone.getPcscfAddress();
1536 }
1537
1538 public void setImsRegistrationState(boolean registered) {
1539 enforceModifyPermission();
1540 mPhone.setImsRegistrationState(registered);
1541 }
1542
1543 /**
Jake Hamby7c27be32014-03-03 13:25:59 -08001544 * Get the preferred network type.
1545 * Used for device configuration by some CDMA operators.
1546 *
1547 * @return the preferred network type, defined in RILConstants.java.
1548 */
1549 @Override
1550 public int getPreferredNetworkType() {
1551 enforceModifyPermission();
1552 if (DBG) log("getPreferredNetworkType");
1553 int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null);
1554 int networkType = (result != null ? result[0] : -1);
1555 if (DBG) log("getPreferredNetworkType: " + networkType);
1556 return networkType;
1557 }
1558
1559 /**
1560 * Set the preferred network type.
1561 * Used for device configuration by some CDMA operators.
1562 *
1563 * @param networkType the preferred network type, defined in RILConstants.java.
1564 * @return true on success; false on any failure.
1565 */
1566 @Override
1567 public boolean setPreferredNetworkType(int networkType) {
1568 enforceModifyPermission();
1569 if (DBG) log("setPreferredNetworkType: type " + networkType);
1570 Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType);
1571 if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
1572 return success;
1573 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001574
1575 /**
Junda Liu787bc7e2014-06-30 13:38:02 -07001576 * Set the CDMA subscription source.
1577 * Used for device supporting both NV and RUIM for CDMA.
1578 *
1579 * @param subscriptionType the subscription type, 0 for RUIM, 1 for NV.
1580 * @return true on success; false on any failure.
1581 */
1582 @Override
1583 public boolean setCdmaSubscription(int subscriptionType) {
1584 enforceModifyPermission();
1585 if (DBG) log("setCdmaSubscription: type " + subscriptionType);
1586 if (subscriptionType != mPhone.CDMA_SUBSCRIPTION_RUIM_SIM &&
1587 subscriptionType != mPhone.CDMA_SUBSCRIPTION_NV) {
1588 loge("setCdmaSubscription: unsupported subscriptionType.");
1589 return false;
1590 }
1591 Boolean success = (Boolean) sendRequest(CMD_SET_CDMA_SUBSCRIPTION, subscriptionType);
1592 if (DBG) log("setCdmaSubscription: " + (success ? "ok" : "fail"));
1593 if (success) {
1594 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1595 Settings.Global.CDMA_SUBSCRIPTION_MODE, subscriptionType);
1596 }
1597 return success;
1598 }
1599
1600 /**
Robert Greenwalted86e582014-05-21 20:03:20 -07001601 * Set mobile data enabled
1602 * Used by the user through settings etc to turn on/off mobile data
1603 *
1604 * @param enable {@code true} turn turn data on, else {@code false}
1605 */
1606 @Override
1607 public void setDataEnabled(boolean enable) {
1608 enforceModifyPermission();
1609 mPhone.setDataEnabled(enable);
1610 }
1611
1612 /**
Robert Greenwalt646120a2014-05-23 11:54:03 -07001613 * Get whether mobile data is enabled.
1614 *
1615 * Note that this used to be available from ConnectivityService, gated by
1616 * ACCESS_NETWORK_STATE permission, so this will accept either that or
1617 * our MODIFY_PHONE_STATE.
Robert Greenwalted86e582014-05-21 20:03:20 -07001618 *
1619 * @return {@code true} if data is enabled else {@code false}
1620 */
1621 @Override
1622 public boolean getDataEnabled() {
Robert Greenwalt646120a2014-05-23 11:54:03 -07001623 try {
1624 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
1625 null);
1626 } catch (Exception e) {
1627 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
1628 null);
1629 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001630 return mPhone.getDataEnabled();
1631 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001632}