blob: 057f8adce33bb03c7e84adc1a9b7ab6c630af31f [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;
Shishir Agrawal60f9c952014-06-23 12:00:43 -070024import android.content.pm.PackageInfo;
25import android.content.pm.PackageManager;
26import android.content.pm.Signature;
Wink Saville36469e72014-06-11 15:17:00 -070027import android.net.ConnectivityManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070028import android.net.Uri;
29import android.os.AsyncResult;
30import android.os.Binder;
31import android.os.Bundle;
32import android.os.Handler;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070033import android.os.IBinder;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070034import android.os.Looper;
35import android.os.Message;
36import android.os.Process;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070037import android.os.RemoteException;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070038import android.os.ServiceManager;
39import android.os.UserHandle;
Ihab Awadf2177b72013-11-25 13:33:23 -080040import android.provider.Settings;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070041import android.telephony.CellInfo;
Jake Hambye994d462014-02-03 13:10:13 -080042import android.telephony.NeighboringCellInfo;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070043import android.telephony.ServiceState;
Wink Saville36469e72014-06-11 15:17:00 -070044import android.telephony.SubscriptionManager;
Ihab Awadf2177b72013-11-25 13:33:23 -080045import android.telephony.TelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070046import android.text.TextUtils;
47import android.util.Log;
Jake Hambye994d462014-02-03 13:10:13 -080048import android.util.Pair;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070049
Shishir Agrawal566b7612013-10-28 14:41:00 -070050import com.android.internal.telephony.CallManager;
51import com.android.internal.telephony.CommandException;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070052import com.android.internal.telephony.Connection;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070053import com.android.internal.telephony.DefaultPhoneNotifier;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070054import com.android.internal.telephony.ITelephony;
Jake Hambye994d462014-02-03 13:10:13 -080055import com.android.internal.telephony.IccCard;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070056import com.android.internal.telephony.Phone;
Wink Saville36469e72014-06-11 15:17:00 -070057import com.android.internal.telephony.PhoneFactory;
58import com.android.internal.telephony.CallManager;
59import com.android.internal.telephony.CommandException;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070060import com.android.internal.telephony.PhoneConstants;
Wink Saville36469e72014-06-11 15:17:00 -070061import com.android.internal.telephony.dataconnection.DctController;
Shishir Agrawal566b7612013-10-28 14:41:00 -070062import com.android.internal.telephony.uicc.IccIoResult;
63import com.android.internal.telephony.uicc.IccUtils;
Shishir Agrawal60f9c952014-06-23 12:00:43 -070064import com.android.internal.telephony.uicc.UiccCarrierPrivilegeRules;
Shishir Agrawal566b7612013-10-28 14:41:00 -070065import com.android.internal.telephony.uicc.UiccController;
Jake Hambye994d462014-02-03 13:10:13 -080066import com.android.internal.util.HexDump;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070067
Wink Saville36469e72014-06-11 15:17:00 -070068import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
69
Santos Cordon7d4ddf62013-07-10 11:58:08 -070070import java.util.ArrayList;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070071import java.util.HashMap;
72import java.util.Iterator;
Jake Hambye994d462014-02-03 13:10:13 -080073import java.util.List;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070074import java.util.Map;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070075
76/**
77 * Implementation of the ITelephony interface.
78 */
Santos Cordon117fee72014-05-16 17:56:12 -070079public class PhoneInterfaceManager extends ITelephony.Stub {
Santos Cordon7d4ddf62013-07-10 11:58:08 -070080 private static final String LOG_TAG = "PhoneInterfaceManager";
81 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
82 private static final boolean DBG_LOC = false;
83
84 // Message codes used with mMainThreadHandler
85 private static final int CMD_HANDLE_PIN_MMI = 1;
86 private static final int CMD_HANDLE_NEIGHBORING_CELL = 2;
87 private static final int EVENT_NEIGHBORING_CELL_DONE = 3;
88 private static final int CMD_ANSWER_RINGING_CALL = 4;
89 private static final int CMD_END_CALL = 5; // not used yet
90 private static final int CMD_SILENCE_RINGER = 6;
Shishir Agrawal566b7612013-10-28 14:41:00 -070091 private static final int CMD_TRANSMIT_APDU = 7;
92 private static final int EVENT_TRANSMIT_APDU_DONE = 8;
93 private static final int CMD_OPEN_CHANNEL = 9;
94 private static final int EVENT_OPEN_CHANNEL_DONE = 10;
95 private static final int CMD_CLOSE_CHANNEL = 11;
96 private static final int EVENT_CLOSE_CHANNEL_DONE = 12;
Jake Hambye994d462014-02-03 13:10:13 -080097 private static final int CMD_NV_READ_ITEM = 13;
98 private static final int EVENT_NV_READ_ITEM_DONE = 14;
99 private static final int CMD_NV_WRITE_ITEM = 15;
100 private static final int EVENT_NV_WRITE_ITEM_DONE = 16;
101 private static final int CMD_NV_WRITE_CDMA_PRL = 17;
102 private static final int EVENT_NV_WRITE_CDMA_PRL_DONE = 18;
103 private static final int CMD_NV_RESET_CONFIG = 19;
104 private static final int EVENT_NV_RESET_CONFIG_DONE = 20;
Jake Hamby7c27be32014-03-03 13:25:59 -0800105 private static final int CMD_GET_PREFERRED_NETWORK_TYPE = 21;
106 private static final int EVENT_GET_PREFERRED_NETWORK_TYPE_DONE = 22;
107 private static final int CMD_SET_PREFERRED_NETWORK_TYPE = 23;
108 private static final int EVENT_SET_PREFERRED_NETWORK_TYPE_DONE = 24;
Sailesh Nepal35b59452014-03-06 09:26:56 -0800109 private static final int CMD_SEND_ENVELOPE = 25;
110 private static final int EVENT_SEND_ENVELOPE_DONE = 26;
Junda Liu787bc7e2014-06-30 13:38:02 -0700111 private static final int CMD_SET_CDMA_SUBSCRIPTION = 27;
112 private static final int EVENT_SET_CDMA_SUBSCRIPTION_DONE = 28;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700113
114 /** The singleton instance. */
115 private static PhoneInterfaceManager sInstance;
116
117 PhoneGlobals mApp;
118 Phone mPhone;
119 CallManager mCM;
120 AppOpsManager mAppOps;
121 MainThreadHandler mMainThreadHandler;
122
123 /**
Shishir Agrawal566b7612013-10-28 14:41:00 -0700124 * A request object to use for transmitting data to an ICC.
125 */
126 private static final class IccAPDUArgument {
127 public int channel, cla, command, p1, p2, p3;
128 public String data;
129
130 public IccAPDUArgument(int channel, int cla, int command,
131 int p1, int p2, int p3, String data) {
132 this.channel = channel;
133 this.cla = cla;
134 this.command = command;
135 this.p1 = p1;
136 this.p2 = p2;
137 this.p3 = p3;
138 this.data = data;
139 }
140 }
141
142 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700143 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
144 * request after sending. The main thread will notify the request when it is complete.
145 */
146 private static final class MainThreadRequest {
147 /** The argument to use for the request */
148 public Object argument;
149 /** The result of the request that is run on the main thread */
150 public Object result;
151
152 public MainThreadRequest(Object argument) {
153 this.argument = argument;
154 }
155 }
156
Sailesh Nepalcc0375f2013-11-13 09:15:18 -0800157 private static final class IncomingThirdPartyCallArgs {
158 public final ComponentName component;
159 public final String callId;
160 public final String callerDisplayName;
161
162 public IncomingThirdPartyCallArgs(ComponentName component, String callId,
163 String callerDisplayName) {
164 this.component = component;
165 this.callId = callId;
166 this.callerDisplayName = callerDisplayName;
167 }
168 }
169
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700170 /**
171 * A handler that processes messages on the main thread in the phone process. Since many
172 * of the Phone calls are not thread safe this is needed to shuttle the requests from the
173 * inbound binder threads to the main thread in the phone process. The Binder thread
174 * may provide a {@link MainThreadRequest} object in the msg.obj field that they are waiting
175 * on, which will be notified when the operation completes and will contain the result of the
176 * request.
177 *
178 * <p>If a MainThreadRequest object is provided in the msg.obj field,
179 * note that request.result must be set to something non-null for the calling thread to
180 * unblock.
181 */
182 private final class MainThreadHandler extends Handler {
183 @Override
184 public void handleMessage(Message msg) {
185 MainThreadRequest request;
186 Message onCompleted;
187 AsyncResult ar;
188
189 switch (msg.what) {
190 case CMD_HANDLE_PIN_MMI:
191 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800192 request.result = mPhone.handlePinMmi((String) request.argument);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700193 // Wake up the requesting thread
194 synchronized (request) {
195 request.notifyAll();
196 }
197 break;
198
199 case CMD_HANDLE_NEIGHBORING_CELL:
200 request = (MainThreadRequest) msg.obj;
201 onCompleted = obtainMessage(EVENT_NEIGHBORING_CELL_DONE,
202 request);
203 mPhone.getNeighboringCids(onCompleted);
204 break;
205
206 case EVENT_NEIGHBORING_CELL_DONE:
207 ar = (AsyncResult) msg.obj;
208 request = (MainThreadRequest) ar.userObj;
209 if (ar.exception == null && ar.result != null) {
210 request.result = ar.result;
211 } else {
212 // create an empty list to notify the waiting thread
Jake Hambye994d462014-02-03 13:10:13 -0800213 request.result = new ArrayList<NeighboringCellInfo>(0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700214 }
215 // Wake up the requesting thread
216 synchronized (request) {
217 request.notifyAll();
218 }
219 break;
220
221 case CMD_ANSWER_RINGING_CALL:
222 answerRingingCallInternal();
223 break;
224
225 case CMD_SILENCE_RINGER:
226 silenceRingerInternal();
227 break;
228
229 case CMD_END_CALL:
230 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800231 boolean hungUp;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700232 int phoneType = mPhone.getPhoneType();
233 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
234 // CDMA: If the user presses the Power button we treat it as
235 // ending the complete call session
236 hungUp = PhoneUtils.hangupRingingAndActive(mPhone);
237 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
238 // GSM: End the call as per the Phone state
239 hungUp = PhoneUtils.hangup(mCM);
240 } else {
241 throw new IllegalStateException("Unexpected phone type: " + phoneType);
242 }
243 if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up"));
244 request.result = hungUp;
245 // Wake up the requesting thread
246 synchronized (request) {
247 request.notifyAll();
248 }
249 break;
250
Shishir Agrawal566b7612013-10-28 14:41:00 -0700251 case CMD_TRANSMIT_APDU:
252 request = (MainThreadRequest) msg.obj;
253 IccAPDUArgument argument = (IccAPDUArgument) request.argument;
254 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_DONE, request);
255 UiccController.getInstance().getUiccCard().iccTransmitApduLogicalChannel(
256 argument.channel, argument.cla, argument.command,
257 argument.p1, argument.p2, argument.p3, argument.data,
258 onCompleted);
259 break;
260
261 case EVENT_TRANSMIT_APDU_DONE:
262 ar = (AsyncResult) msg.obj;
263 request = (MainThreadRequest) ar.userObj;
264 if (ar.exception == null && ar.result != null) {
265 request.result = ar.result;
266 } else {
267 request.result = new IccIoResult(0x6F, 0, (byte[])null);
268 if (ar.result == null) {
269 loge("iccTransmitApduLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800270 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700271 loge("iccTransmitApduLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800272 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700273 } else {
274 loge("iccTransmitApduLogicalChannel: Unknown exception");
275 }
276 }
277 synchronized (request) {
278 request.notifyAll();
279 }
280 break;
281
Derek Tan4d5e5c12014-02-04 11:54:58 -0800282 case CMD_SEND_ENVELOPE:
283 request = (MainThreadRequest) msg.obj;
284 onCompleted = obtainMessage(EVENT_SEND_ENVELOPE_DONE, request);
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700285 UiccController.getInstance().getUiccCard().sendEnvelopeWithStatus(
Derek Tan4d5e5c12014-02-04 11:54:58 -0800286 (String)request.argument, onCompleted);
287 break;
288
289 case EVENT_SEND_ENVELOPE_DONE:
290 ar = (AsyncResult) msg.obj;
291 request = (MainThreadRequest) ar.userObj;
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700292 if (ar.exception == null && ar.result != null) {
293 request.result = ar.result;
Derek Tan4d5e5c12014-02-04 11:54:58 -0800294 } else {
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700295 request.result = new IccIoResult(0x6F, 0, (byte[])null);
296 if (ar.result == null) {
297 loge("sendEnvelopeWithStatus: Empty response");
298 } else if (ar.exception instanceof CommandException) {
299 loge("sendEnvelopeWithStatus: CommandException: " +
300 ar.exception);
301 } else {
302 loge("sendEnvelopeWithStatus: exception:" + ar.exception);
303 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800304 }
305 synchronized (request) {
306 request.notifyAll();
307 }
308 break;
309
Shishir Agrawal566b7612013-10-28 14:41:00 -0700310 case CMD_OPEN_CHANNEL:
311 request = (MainThreadRequest) msg.obj;
312 onCompleted = obtainMessage(EVENT_OPEN_CHANNEL_DONE, request);
313 UiccController.getInstance().getUiccCard().iccOpenLogicalChannel(
314 (String)request.argument, onCompleted);
315 break;
316
317 case EVENT_OPEN_CHANNEL_DONE:
318 ar = (AsyncResult) msg.obj;
319 request = (MainThreadRequest) ar.userObj;
320 if (ar.exception == null && ar.result != null) {
Jake Hambye994d462014-02-03 13:10:13 -0800321 request.result = ((int[]) ar.result)[0];
Shishir Agrawal566b7612013-10-28 14:41:00 -0700322 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800323 request.result = -1;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700324 if (ar.result == null) {
325 loge("iccOpenLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800326 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700327 loge("iccOpenLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800328 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700329 } else {
330 loge("iccOpenLogicalChannel: Unknown exception");
331 }
332 }
333 synchronized (request) {
334 request.notifyAll();
335 }
336 break;
337
338 case CMD_CLOSE_CHANNEL:
339 request = (MainThreadRequest) msg.obj;
340 onCompleted = obtainMessage(EVENT_CLOSE_CHANNEL_DONE,
341 request);
342 UiccController.getInstance().getUiccCard().iccCloseLogicalChannel(
Jake Hambye994d462014-02-03 13:10:13 -0800343 (Integer) request.argument,
Shishir Agrawal566b7612013-10-28 14:41:00 -0700344 onCompleted);
345 break;
346
347 case EVENT_CLOSE_CHANNEL_DONE:
Jake Hambye994d462014-02-03 13:10:13 -0800348 handleNullReturnEvent(msg, "iccCloseLogicalChannel");
349 break;
350
351 case CMD_NV_READ_ITEM:
352 request = (MainThreadRequest) msg.obj;
353 onCompleted = obtainMessage(EVENT_NV_READ_ITEM_DONE, request);
354 mPhone.nvReadItem((Integer) request.argument, onCompleted);
355 break;
356
357 case EVENT_NV_READ_ITEM_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700358 ar = (AsyncResult) msg.obj;
359 request = (MainThreadRequest) ar.userObj;
Jake Hambye994d462014-02-03 13:10:13 -0800360 if (ar.exception == null && ar.result != null) {
361 request.result = ar.result; // String
Shishir Agrawal566b7612013-10-28 14:41:00 -0700362 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800363 request.result = "";
364 if (ar.result == null) {
365 loge("nvReadItem: Empty response");
366 } else if (ar.exception instanceof CommandException) {
367 loge("nvReadItem: CommandException: " +
368 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700369 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800370 loge("nvReadItem: Unknown exception");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700371 }
372 }
373 synchronized (request) {
374 request.notifyAll();
375 }
376 break;
377
Jake Hambye994d462014-02-03 13:10:13 -0800378 case CMD_NV_WRITE_ITEM:
379 request = (MainThreadRequest) msg.obj;
380 onCompleted = obtainMessage(EVENT_NV_WRITE_ITEM_DONE, request);
381 Pair<Integer, String> idValue = (Pair<Integer, String>) request.argument;
382 mPhone.nvWriteItem(idValue.first, idValue.second, onCompleted);
383 break;
384
385 case EVENT_NV_WRITE_ITEM_DONE:
386 handleNullReturnEvent(msg, "nvWriteItem");
387 break;
388
389 case CMD_NV_WRITE_CDMA_PRL:
390 request = (MainThreadRequest) msg.obj;
391 onCompleted = obtainMessage(EVENT_NV_WRITE_CDMA_PRL_DONE, request);
392 mPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
393 break;
394
395 case EVENT_NV_WRITE_CDMA_PRL_DONE:
396 handleNullReturnEvent(msg, "nvWriteCdmaPrl");
397 break;
398
399 case CMD_NV_RESET_CONFIG:
400 request = (MainThreadRequest) msg.obj;
401 onCompleted = obtainMessage(EVENT_NV_RESET_CONFIG_DONE, request);
402 mPhone.nvResetConfig((Integer) request.argument, onCompleted);
403 break;
404
405 case EVENT_NV_RESET_CONFIG_DONE:
406 handleNullReturnEvent(msg, "nvResetConfig");
407 break;
408
Jake Hamby7c27be32014-03-03 13:25:59 -0800409 case CMD_GET_PREFERRED_NETWORK_TYPE:
410 request = (MainThreadRequest) msg.obj;
411 onCompleted = obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE_DONE, request);
412 mPhone.getPreferredNetworkType(onCompleted);
413 break;
414
415 case EVENT_GET_PREFERRED_NETWORK_TYPE_DONE:
416 ar = (AsyncResult) msg.obj;
417 request = (MainThreadRequest) ar.userObj;
418 if (ar.exception == null && ar.result != null) {
419 request.result = ar.result; // Integer
420 } else {
421 request.result = -1;
422 if (ar.result == null) {
423 loge("getPreferredNetworkType: Empty response");
424 } else if (ar.exception instanceof CommandException) {
425 loge("getPreferredNetworkType: CommandException: " +
426 ar.exception);
427 } else {
428 loge("getPreferredNetworkType: Unknown exception");
429 }
430 }
431 synchronized (request) {
432 request.notifyAll();
433 }
434 break;
435
436 case CMD_SET_PREFERRED_NETWORK_TYPE:
437 request = (MainThreadRequest) msg.obj;
438 onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);
439 int networkType = (Integer) request.argument;
440 mPhone.setPreferredNetworkType(networkType, onCompleted);
441 break;
442
443 case EVENT_SET_PREFERRED_NETWORK_TYPE_DONE:
444 handleNullReturnEvent(msg, "setPreferredNetworkType");
445 break;
446
Junda Liu787bc7e2014-06-30 13:38:02 -0700447 case CMD_SET_CDMA_SUBSCRIPTION:
448 request = (MainThreadRequest) msg.obj;
449 onCompleted = obtainMessage(EVENT_SET_CDMA_SUBSCRIPTION_DONE, request);
450 int subscriptionType = (Integer) request.argument;
451 mPhone.setCdmaSubscription(subscriptionType, onCompleted);
452 break;
453
454 case EVENT_SET_CDMA_SUBSCRIPTION_DONE:
455 handleNullReturnEvent(msg, "setCdmaSubscription");
456 break;
457
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700458 default:
459 Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
460 break;
461 }
462 }
Jake Hambye994d462014-02-03 13:10:13 -0800463
464 private void handleNullReturnEvent(Message msg, String command) {
465 AsyncResult ar = (AsyncResult) msg.obj;
466 MainThreadRequest request = (MainThreadRequest) ar.userObj;
467 if (ar.exception == null) {
468 request.result = true;
469 } else {
470 request.result = false;
471 if (ar.exception instanceof CommandException) {
472 loge(command + ": CommandException: " + ar.exception);
473 } else {
474 loge(command + ": Unknown exception");
475 }
476 }
477 synchronized (request) {
478 request.notifyAll();
479 }
480 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700481 }
482
483 /**
484 * Posts the specified command to be executed on the main thread,
485 * waits for the request to complete, and returns the result.
486 * @see #sendRequestAsync
487 */
488 private Object sendRequest(int command, Object argument) {
Santos Cordon500b0e02014-06-17 10:33:33 -0700489 return sendRequest(command, argument, null);
Wink Saville36469e72014-06-11 15:17:00 -0700490 }
491
492 /**
493 * Posts the specified command to be executed on the main thread,
494 * waits for the request to complete, and returns the result.
495 * @see #sendRequestAsync
496 */
497 private Object sendRequest(int command, Object argument, Object argument2) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700498 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
499 throw new RuntimeException("This method will deadlock if called from the main thread.");
500 }
501
502 MainThreadRequest request = new MainThreadRequest(argument);
503 Message msg = mMainThreadHandler.obtainMessage(command, request);
504 msg.sendToTarget();
505
506 // Wait for the request to complete
507 synchronized (request) {
508 while (request.result == null) {
509 try {
510 request.wait();
511 } catch (InterruptedException e) {
512 // Do nothing, go back and wait until the request is complete
513 }
514 }
515 }
516 return request.result;
517 }
518
519 /**
520 * Asynchronous ("fire and forget") version of sendRequest():
521 * Posts the specified command to be executed on the main thread, and
522 * returns immediately.
523 * @see #sendRequest
524 */
525 private void sendRequestAsync(int command) {
526 mMainThreadHandler.sendEmptyMessage(command);
527 }
528
529 /**
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -0700530 * Same as {@link #sendRequestAsync(int)} except it takes an argument.
531 * @see {@link #sendRequest(int,Object)}
532 */
533 private void sendRequestAsync(int command, Object argument) {
534 MainThreadRequest request = new MainThreadRequest(argument);
535 Message msg = mMainThreadHandler.obtainMessage(command, request);
536 msg.sendToTarget();
537 }
538
539 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700540 * Initialize the singleton PhoneInterfaceManager instance.
541 * This is only done once, at startup, from PhoneApp.onCreate().
542 */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700543 /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700544 synchronized (PhoneInterfaceManager.class) {
545 if (sInstance == null) {
Sailesh Nepal194161e2014-07-03 08:57:44 -0700546 sInstance = new PhoneInterfaceManager(app, phone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700547 } else {
548 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
549 }
550 return sInstance;
551 }
552 }
553
554 /** Private constructor; @see init() */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700555 private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
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();
561 publish();
562 }
563
564 private void publish() {
565 if (DBG) log("publish: " + this);
566
567 ServiceManager.addService("phone", this);
568 }
569
Wink Saville36469e72014-06-11 15:17:00 -0700570 // returns phone associated with the subId.
571 // getPhone(0) returns default phone in single SIM mode.
572 private Phone getPhone(long subId) {
573 // FIXME: hack for the moment
574 return mPhone;
575 // return PhoneUtils.getPhoneUsingSubId(subId);
576 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700577 //
578 // Implementation of the ITelephony interface.
579 //
580
581 public void dial(String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700582 dialUsingSubId(getPreferredVoiceSubscription(), number);
583 }
584
585 public void dialUsingSubId(long subId, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700586 if (DBG) log("dial: " + number);
587 // No permission check needed here: This is just a wrapper around the
588 // ACTION_DIAL intent, which is available to any app since it puts up
589 // the UI before it does anything.
590
591 String url = createTelUrl(number);
592 if (url == null) {
593 return;
594 }
595
596 // PENDING: should we just silently fail if phone is offhook or ringing?
Wink Saville36469e72014-06-11 15:17:00 -0700597 PhoneConstants.State state = mCM.getState(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700598 if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
599 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
600 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Wink Saville36469e72014-06-11 15:17:00 -0700601 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700602 mApp.startActivity(intent);
603 }
604 }
605
606 public void call(String callingPackage, String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700607 callUsingSubId(getPreferredVoiceSubscription(), callingPackage, number);
608 }
609
610 public void callUsingSubId(long subId, String callingPackage, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700611 if (DBG) log("call: " + number);
612
613 // This is just a wrapper around the ACTION_CALL intent, but we still
614 // need to do a permission check since we're calling startActivity()
615 // from the context of the phone app.
616 enforceCallPermission();
617
618 if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
619 != AppOpsManager.MODE_ALLOWED) {
620 return;
621 }
622
623 String url = createTelUrl(number);
624 if (url == null) {
625 return;
626 }
627
628 Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
Wink Saville36469e72014-06-11 15:17:00 -0700629 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700630 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
631 mApp.startActivity(intent);
632 }
633
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700634 /**
635 * End a call based on call state
636 * @return true is a call was ended
637 */
638 public boolean endCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700639 return endCallUsingSubId(getDefaultSubscription());
640 }
641
642 /**
643 * End a call based on the call state of the subId
644 * @return true is a call was ended
645 */
646 public boolean endCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700647 enforceCallPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700648 return (Boolean) sendRequest(CMD_END_CALL, subId, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700649 }
650
651 public void answerRingingCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700652 answerRingingCallUsingSubId(getDefaultSubscription());
653 }
654
655 public void answerRingingCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700656 if (DBG) log("answerRingingCall...");
657 // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
658 // but that can probably wait till the big TelephonyManager API overhaul.
659 // For now, protect this call with the MODIFY_PHONE_STATE permission.
660 enforceModifyPermission();
661 sendRequestAsync(CMD_ANSWER_RINGING_CALL);
662 }
663
664 /**
665 * Make the actual telephony calls to implement answerRingingCall().
666 * This should only be called from the main thread of the Phone app.
667 * @see #answerRingingCall
668 *
669 * TODO: it would be nice to return true if we answered the call, or
670 * false if there wasn't actually a ringing incoming call, or some
671 * other error occurred. (In other words, pass back the return value
672 * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
673 * But that would require calling this method via sendRequest() rather
674 * than sendRequestAsync(), and right now we don't actually *need* that
675 * return value, so let's just return void for now.
676 */
677 private void answerRingingCallInternal() {
678 final boolean hasRingingCall = !mPhone.getRingingCall().isIdle();
679 if (hasRingingCall) {
680 final boolean hasActiveCall = !mPhone.getForegroundCall().isIdle();
681 final boolean hasHoldingCall = !mPhone.getBackgroundCall().isIdle();
682 if (hasActiveCall && hasHoldingCall) {
683 // Both lines are in use!
684 // TODO: provide a flag to let the caller specify what
685 // policy to use if both lines are in use. (The current
686 // behavior is hardwired to "answer incoming, end ongoing",
687 // which is how the CALL button is specced to behave.)
688 PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
689 return;
690 } else {
691 // answerCall() will automatically hold the current active
692 // call, if there is one.
693 PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
694 return;
695 }
696 } else {
697 // No call was ringing.
698 return;
699 }
700 }
701
702 public void silenceRinger() {
703 if (DBG) log("silenceRinger...");
704 // TODO: find a more appropriate permission to check here.
705 // (That can probably wait till the big TelephonyManager API overhaul.
706 // For now, protect this call with the MODIFY_PHONE_STATE permission.)
707 enforceModifyPermission();
708 sendRequestAsync(CMD_SILENCE_RINGER);
709 }
710
711 /**
712 * Internal implemenation of silenceRinger().
713 * This should only be called from the main thread of the Phone app.
714 * @see #silenceRinger
715 */
716 private void silenceRingerInternal() {
717 if ((mCM.getState() == PhoneConstants.State.RINGING)
718 && mApp.notifier.isRinging()) {
719 // Ringer is actually playing, so silence it.
720 if (DBG) log("silenceRingerInternal: silencing...");
721 mApp.notifier.silenceRinger();
722 }
723 }
724
725 public boolean isOffhook() {
Wink Saville36469e72014-06-11 15:17:00 -0700726 return isOffhookUsingSubId(getDefaultSubscription());
727 }
728
729 public boolean isOffhookUsingSubId(long subId) {
730 return (getPhone(subId).getState() == PhoneConstants.State.OFFHOOK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700731 }
732
733 public boolean isRinging() {
Wink Saville36469e72014-06-11 15:17:00 -0700734 return (isRingingUsingSubId(getDefaultSubscription()));
735 }
736
737 public boolean isRingingUsingSubId(long subId) {
738 return (getPhone(subId).getState() == PhoneConstants.State.RINGING);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700739 }
740
741 public boolean isIdle() {
Wink Saville36469e72014-06-11 15:17:00 -0700742 return isIdleUsingSubId(getDefaultSubscription());
743 }
744
745 public boolean isIdleUsingSubId(long subId) {
746 return (getPhone(subId).getState() == PhoneConstants.State.IDLE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700747 }
748
749 public boolean isSimPinEnabled() {
750 enforceReadPermission();
751 return (PhoneGlobals.getInstance().isSimPinEnabled());
752 }
753
754 public boolean supplyPin(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700755 return supplyPinUsingSubId(getDefaultSubscription(), pin);
756 }
757
758 public boolean supplyPinUsingSubId(long subId, String pin) {
759 int [] resultArray = supplyPinReportResultUsingSubId(subId, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700760 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
761 }
762
763 public boolean supplyPuk(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700764 return supplyPukUsingSubId(getDefaultSubscription(), puk, pin);
765 }
766
767 public boolean supplyPukUsingSubId(long subId, String puk, String pin) {
768 int [] resultArray = supplyPukReportResultUsingSubId(subId, puk, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700769 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
770 }
771
772 /** {@hide} */
773 public int[] supplyPinReportResult(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700774 return supplyPinReportResultUsingSubId(getDefaultSubscription(), pin);
775 }
776
777 public int[] supplyPinReportResultUsingSubId(long subId, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700778 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700779 final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700780 checkSimPin.start();
781 return checkSimPin.unlockSim(null, pin);
782 }
783
Wink Saville9de0f752013-10-22 19:04:03 -0700784 /** {@hide} */
785 public int[] supplyPukReportResult(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700786 return supplyPukReportResultUsingSubId(getDefaultSubscription(), puk, pin);
787 }
788
789 public int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700790 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700791 final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700792 checkSimPuk.start();
793 return checkSimPuk.unlockSim(puk, pin);
794 }
795
796 /**
Wink Saville9de0f752013-10-22 19:04:03 -0700797 * Helper thread to turn async call to SimCard#supplyPin into
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700798 * a synchronous one.
799 */
800 private static class UnlockSim extends Thread {
801
802 private final IccCard mSimCard;
803
804 private boolean mDone = false;
Wink Saville9de0f752013-10-22 19:04:03 -0700805 private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
806 private int mRetryCount = -1;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700807
808 // For replies from SimCard interface
809 private Handler mHandler;
810
811 // For async handler to identify request type
812 private static final int SUPPLY_PIN_COMPLETE = 100;
813
814 public UnlockSim(IccCard simCard) {
815 mSimCard = simCard;
816 }
817
818 @Override
819 public void run() {
820 Looper.prepare();
821 synchronized (UnlockSim.this) {
822 mHandler = new Handler() {
823 @Override
824 public void handleMessage(Message msg) {
825 AsyncResult ar = (AsyncResult) msg.obj;
826 switch (msg.what) {
827 case SUPPLY_PIN_COMPLETE:
828 Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
829 synchronized (UnlockSim.this) {
Wink Saville9de0f752013-10-22 19:04:03 -0700830 mRetryCount = msg.arg1;
831 if (ar.exception != null) {
832 if (ar.exception instanceof CommandException &&
833 ((CommandException)(ar.exception)).getCommandError()
834 == CommandException.Error.PASSWORD_INCORRECT) {
835 mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
836 } else {
837 mResult = PhoneConstants.PIN_GENERAL_FAILURE;
838 }
839 } else {
840 mResult = PhoneConstants.PIN_RESULT_SUCCESS;
841 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700842 mDone = true;
843 UnlockSim.this.notifyAll();
844 }
845 break;
846 }
847 }
848 };
849 UnlockSim.this.notifyAll();
850 }
851 Looper.loop();
852 }
853
854 /*
855 * Use PIN or PUK to unlock SIM card
856 *
857 * If PUK is null, unlock SIM card with PIN
858 *
859 * If PUK is not null, unlock SIM card with PUK and set PIN code
860 */
Wink Saville9de0f752013-10-22 19:04:03 -0700861 synchronized int[] unlockSim(String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700862
863 while (mHandler == null) {
864 try {
865 wait();
866 } catch (InterruptedException e) {
867 Thread.currentThread().interrupt();
868 }
869 }
870 Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
871
872 if (puk == null) {
873 mSimCard.supplyPin(pin, callback);
874 } else {
875 mSimCard.supplyPuk(puk, pin, callback);
876 }
877
878 while (!mDone) {
879 try {
880 Log.d(LOG_TAG, "wait for done");
881 wait();
882 } catch (InterruptedException e) {
883 // Restore the interrupted status
884 Thread.currentThread().interrupt();
885 }
886 }
887 Log.d(LOG_TAG, "done");
Wink Saville9de0f752013-10-22 19:04:03 -0700888 int[] resultArray = new int[2];
889 resultArray[0] = mResult;
890 resultArray[1] = mRetryCount;
891 return resultArray;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700892 }
893 }
894
895 public void updateServiceLocation() {
Wink Saville36469e72014-06-11 15:17:00 -0700896 updateServiceLocationUsingSubId(getDefaultSubscription());
897
898 }
899
900 public void updateServiceLocationUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700901 // No permission check needed here: this call is harmless, and it's
902 // needed for the ServiceState.requestStateUpdate() call (which is
903 // already intentionally exposed to 3rd parties.)
Wink Saville36469e72014-06-11 15:17:00 -0700904 getPhone(subId).updateServiceLocation();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700905 }
906
907 public boolean isRadioOn() {
Wink Saville36469e72014-06-11 15:17:00 -0700908 return isRadioOnUsingSubId(getDefaultSubscription());
909 }
910
911 public boolean isRadioOnUsingSubId(long subId) {
912 return getPhone(subId).getServiceState().getState() != ServiceState.STATE_POWER_OFF;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700913 }
914
915 public void toggleRadioOnOff() {
Wink Saville36469e72014-06-11 15:17:00 -0700916 toggleRadioOnOffUsingSubId(getDefaultSubscription());
917
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700918 }
Wink Saville36469e72014-06-11 15:17:00 -0700919
920 public void toggleRadioOnOffUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700921 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700922 getPhone(subId).setRadioPower(!isRadioOnUsingSubId(subId));
923 }
924
925 public boolean setRadio(boolean turnOn) {
926 return setRadioUsingSubId(getDefaultSubscription(), turnOn);
927 }
928
929 public boolean setRadioUsingSubId(long subId, boolean turnOn) {
930 enforceModifyPermission();
931 if ((getPhone(subId).getServiceState().getState() !=
932 ServiceState.STATE_POWER_OFF) != turnOn) {
933 toggleRadioOnOffUsingSubId(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700934 }
935 return true;
936 }
Wink Saville36469e72014-06-11 15:17:00 -0700937
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700938 public boolean setRadioPower(boolean turnOn) {
Wink Saville36469e72014-06-11 15:17:00 -0700939 return setRadioPowerUsingSubId(getDefaultSubscription(), turnOn);
940 }
941
942 public boolean setRadioPowerUsingSubId(long subId, boolean turnOn) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700943 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700944 getPhone(subId).setRadioPower(turnOn);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700945 return true;
946 }
947
Wink Saville36469e72014-06-11 15:17:00 -0700948 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700949 public boolean enableDataConnectivity() {
950 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700951 long subId = SubscriptionManager.getDefaultDataSubId();
952 getPhone(subId).setDataEnabled(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700953 return true;
954 }
955
Wink Saville36469e72014-06-11 15:17:00 -0700956 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700957 public boolean disableDataConnectivity() {
958 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700959 long subId = SubscriptionManager.getDefaultDataSubId();
960 getPhone(subId).setDataEnabled(false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700961 return true;
962 }
963
Wink Saville36469e72014-06-11 15:17:00 -0700964 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700965 public boolean isDataConnectivityPossible() {
Wink Saville36469e72014-06-11 15:17:00 -0700966 long subId = SubscriptionManager.getDefaultDataSubId();
967 return getPhone(subId).isDataConnectivityPossible();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700968 }
969
970 public boolean handlePinMmi(String dialString) {
Wink Saville36469e72014-06-11 15:17:00 -0700971 return handlePinMmiUsingSubId(getDefaultSubscription(), dialString);
972 }
973
974 public boolean handlePinMmiUsingSubId(long subId, String dialString) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700975 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700976 return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700977 }
978
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700979 public int getCallState() {
Wink Saville36469e72014-06-11 15:17:00 -0700980 return getCallStateUsingSubId(getDefaultSubscription());
981 }
982
983 public int getCallStateUsingSubId(long subId) {
984 return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700985 }
986
987 public int getDataState() {
Wink Saville36469e72014-06-11 15:17:00 -0700988 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
989 return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700990 }
991
992 public int getDataActivity() {
Wink Saville36469e72014-06-11 15:17:00 -0700993 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
994 return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700995 }
996
997 @Override
998 public Bundle getCellLocation() {
999 try {
1000 mApp.enforceCallingOrSelfPermission(
1001 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1002 } catch (SecurityException e) {
1003 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1004 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1005 // is the weaker precondition
1006 mApp.enforceCallingOrSelfPermission(
1007 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1008 }
1009
Jake Hambye994d462014-02-03 13:10:13 -08001010 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001011 if (DBG_LOC) log("getCellLocation: is active user");
1012 Bundle data = new Bundle();
1013 mPhone.getCellLocation().fillInNotifierBundle(data);
1014 return data;
1015 } else {
1016 if (DBG_LOC) log("getCellLocation: suppress non-active user");
1017 return null;
1018 }
1019 }
1020
1021 @Override
1022 public void enableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001023 enableLocationUpdatesUsingSubId(getDefaultSubscription());
1024 }
1025
1026 public void enableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001027 mApp.enforceCallingOrSelfPermission(
1028 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001029 getPhone(subId).enableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001030 }
1031
1032 @Override
1033 public void disableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001034 disableLocationUpdatesUsingSubId(getDefaultSubscription());
1035 }
1036
1037 public void disableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001038 mApp.enforceCallingOrSelfPermission(
1039 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001040 getPhone(subId).disableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001041 }
1042
1043 @Override
1044 @SuppressWarnings("unchecked")
1045 public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1046 try {
1047 mApp.enforceCallingOrSelfPermission(
1048 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1049 } catch (SecurityException e) {
1050 // If we have ACCESS_FINE_LOCATION permission, skip the check
1051 // for ACCESS_COARSE_LOCATION
1052 // A failure should throw the SecurityException from
1053 // ACCESS_COARSE_LOCATION since this is the weaker precondition
1054 mApp.enforceCallingOrSelfPermission(
1055 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1056 }
1057
1058 if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1059 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1060 return null;
1061 }
Jake Hambye994d462014-02-03 13:10:13 -08001062 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001063 if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1064
1065 ArrayList<NeighboringCellInfo> cells = null;
1066
1067 try {
1068 cells = (ArrayList<NeighboringCellInfo>) sendRequest(
Wink Saville36469e72014-06-11 15:17:00 -07001069 CMD_HANDLE_NEIGHBORING_CELL, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001070 } catch (RuntimeException e) {
Wink Saville36469e72014-06-11 15:17:00 -07001071 Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001072 }
1073 return cells;
1074 } else {
1075 if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1076 return null;
1077 }
1078 }
1079
1080
1081 @Override
1082 public List<CellInfo> getAllCellInfo() {
1083 try {
1084 mApp.enforceCallingOrSelfPermission(
1085 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1086 } catch (SecurityException e) {
1087 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1088 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1089 // is the weaker precondition
1090 mApp.enforceCallingOrSelfPermission(
1091 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1092 }
1093
Jake Hambye994d462014-02-03 13:10:13 -08001094 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001095 if (DBG_LOC) log("getAllCellInfo: is active user");
1096 return mPhone.getAllCellInfo();
1097 } else {
1098 if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1099 return null;
1100 }
1101 }
1102
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -07001103 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001104 public void setCellInfoListRate(int rateInMillis) {
1105 mPhone.setCellInfoListRate(rateInMillis);
1106 }
1107
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001108 //
1109 // Internal helper methods.
1110 //
1111
Jake Hambye994d462014-02-03 13:10:13 -08001112 private static boolean checkIfCallerIsSelfOrForegroundUser() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001113 boolean ok;
1114
1115 boolean self = Binder.getCallingUid() == Process.myUid();
1116 if (!self) {
1117 // Get the caller's user id then clear the calling identity
1118 // which will be restored in the finally clause.
1119 int callingUser = UserHandle.getCallingUserId();
1120 long ident = Binder.clearCallingIdentity();
1121
1122 try {
1123 // With calling identity cleared the current user is the foreground user.
1124 int foregroundUser = ActivityManager.getCurrentUser();
1125 ok = (foregroundUser == callingUser);
1126 if (DBG_LOC) {
1127 log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1128 + " callingUser=" + callingUser + " ok=" + ok);
1129 }
1130 } catch (Exception ex) {
1131 if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1132 ok = false;
1133 } finally {
1134 Binder.restoreCallingIdentity(ident);
1135 }
1136 } else {
1137 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1138 ok = true;
1139 }
1140 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1141 return ok;
1142 }
1143
1144 /**
1145 * Make sure the caller has the READ_PHONE_STATE permission.
1146 *
1147 * @throws SecurityException if the caller does not have the required permission
1148 */
1149 private void enforceReadPermission() {
1150 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
1151 }
1152
1153 /**
1154 * Make sure the caller has the MODIFY_PHONE_STATE permission.
1155 *
1156 * @throws SecurityException if the caller does not have the required permission
1157 */
1158 private void enforceModifyPermission() {
1159 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1160 }
1161
1162 /**
Junda Liua2e36012014-07-09 18:30:01 -07001163 * Make sure either system app or the caller has carrier privilege.
1164 *
1165 * @throws SecurityException if the caller does not have the required permission/privilege
1166 */
1167 private void enforceModifyPermissionOrCarrierPrivilege() {
1168 try {
1169 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1170 } catch (SecurityException e) {
1171 log("No modify permission, check carrier privilege next.");
1172 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1173 loge("No Carrier Privilege.");
1174 throw new SecurityException("No modify permission or carrier privilege.");
1175 }
1176 }
1177 }
1178
1179 /**
1180 * Make sure the caller has carrier privilege.
1181 *
1182 * @throws SecurityException if the caller does not have the required permission
1183 */
1184 private void enforceCarrierPrivilege() {
1185 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1186 loge("No Carrier Privilege.");
1187 throw new SecurityException("No Carrier Privilege.");
1188 }
1189 }
1190
1191 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001192 * Make sure the caller has the CALL_PHONE permission.
1193 *
1194 * @throws SecurityException if the caller does not have the required permission
1195 */
1196 private void enforceCallPermission() {
1197 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1198 }
1199
Shishir Agrawal566b7612013-10-28 14:41:00 -07001200 /**
Gabriel Peal36ebb0d2014-03-20 09:20:43 -07001201 * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1202 *
1203 * @throws SecurityException if the caller does not have the required permission
1204 */
1205 private void enforcePrivilegedPhoneStatePermission() {
1206 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1207 null);
1208 }
1209
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001210 private String createTelUrl(String number) {
1211 if (TextUtils.isEmpty(number)) {
1212 return null;
1213 }
1214
Jake Hambye994d462014-02-03 13:10:13 -08001215 return "tel:" + number;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001216 }
1217
Ihab Awadf9e92732013-12-05 18:02:52 -08001218 private static void log(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001219 Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1220 }
1221
Ihab Awadf9e92732013-12-05 18:02:52 -08001222 private static void loge(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001223 Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1224 }
1225
1226 public int getActivePhoneType() {
Wink Saville36469e72014-06-11 15:17:00 -07001227 return getActivePhoneTypeUsingSubId(getDefaultSubscription());
1228 }
1229
1230 public int getActivePhoneTypeUsingSubId(long subId) {
1231 return getPhone(subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001232 }
1233
1234 /**
1235 * Returns the CDMA ERI icon index to display
1236 */
1237 public int getCdmaEriIconIndex() {
Wink Saville36469e72014-06-11 15:17:00 -07001238 return getCdmaEriIconIndexUsingSubId(getDefaultSubscription());
1239
1240 }
1241
1242 public int getCdmaEriIconIndexUsingSubId(long subId) {
1243 return getPhone(subId).getCdmaEriIconIndex();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001244 }
1245
1246 /**
1247 * Returns the CDMA ERI icon mode,
1248 * 0 - ON
1249 * 1 - FLASHING
1250 */
1251 public int getCdmaEriIconMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001252 return getCdmaEriIconModeUsingSubId(getDefaultSubscription());
1253 }
1254
1255 public int getCdmaEriIconModeUsingSubId(long subId) {
1256 return getPhone(subId).getCdmaEriIconMode();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001257 }
1258
1259 /**
1260 * Returns the CDMA ERI text,
1261 */
1262 public String getCdmaEriText() {
Wink Saville36469e72014-06-11 15:17:00 -07001263 return getCdmaEriTextUsingSubId(getDefaultSubscription());
1264 }
1265
1266 public String getCdmaEriTextUsingSubId(long subId) {
1267 return getPhone(subId).getCdmaEriText();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001268 }
1269
1270 /**
1271 * Returns true if CDMA provisioning needs to run.
1272 */
1273 public boolean needsOtaServiceProvisioning() {
1274 return mPhone.needsOtaServiceProvisioning();
1275 }
1276
1277 /**
1278 * Returns the unread count of voicemails
1279 */
1280 public int getVoiceMessageCount() {
Wink Saville36469e72014-06-11 15:17:00 -07001281 return getVoiceMessageCountUsingSubId(getDefaultSubscription());
1282 }
1283
1284 /**
1285 * Returns the unread count of voicemails for a subId
1286 */
1287 public int getVoiceMessageCountUsingSubId( long subId) {
1288 return getPhone(subId).getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001289 }
1290
1291 /**
1292 * Returns the data network type
1293 *
1294 * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1295 */
1296 @Override
1297 public int getNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001298 return getNetworkTypeUsingSubId(getDefaultSubscription());
1299 }
1300
1301 /**
1302 * Returns the network type for a subId
1303 */
1304 @Override
1305 public int getNetworkTypeUsingSubId(long subId) {
1306 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001307 }
1308
1309 /**
1310 * Returns the data network type
1311 */
1312 @Override
1313 public int getDataNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001314 return getDataNetworkTypeUsingSubId(getDefaultSubscription());
1315 }
1316
1317 /**
1318 * Returns the data network type for a subId
1319 */
1320 @Override
1321 public int getDataNetworkTypeUsingSubId(long subId) {
1322 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001323 }
1324
1325 /**
1326 * Returns the data network type
1327 */
1328 @Override
1329 public int getVoiceNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001330 return getVoiceNetworkTypeUsingSubId(getDefaultSubscription());
1331 }
1332
1333 /**
1334 * Returns the Voice network type for a subId
1335 */
1336 @Override
1337 public int getVoiceNetworkTypeUsingSubId(long subId) {
1338 return getPhone(subId).getServiceState().getVoiceNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001339 }
1340
1341 /**
1342 * @return true if a ICC card is present
1343 */
1344 public boolean hasIccCard() {
Wink Saville36469e72014-06-11 15:17:00 -07001345 // FIXME Make changes to pass defaultSimId of type int
1346 return hasIccCardUsingSlotId(getDefaultSubscription());
1347 }
1348
1349 /**
1350 * @return true if a ICC card is present for a slotId
1351 */
1352 public boolean hasIccCardUsingSlotId(long slotId) {
1353 return getPhone(slotId).getIccCard().hasIccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001354 }
1355
1356 /**
1357 * Return if the current radio is LTE on CDMA. This
1358 * is a tri-state return value as for a period of time
1359 * the mode may be unknown.
1360 *
1361 * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
Jake Hambye994d462014-02-03 13:10:13 -08001362 * or {@link Phone#LTE_ON_CDMA_TRUE}
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001363 */
1364 public int getLteOnCdmaMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001365 return getLteOnCdmaModeUsingSubId(getDefaultSubscription());
1366 }
1367
1368 public int getLteOnCdmaModeUsingSubId(long subId) {
1369 return getPhone(subId).getLteOnCdmaMode();
1370 }
1371
1372 public void setPhone(Phone phone) {
1373 mPhone = phone;
1374 }
1375
1376 /**
1377 * {@hide}
1378 * Returns Default subId, 0 in the case of single standby.
1379 */
1380 private long getDefaultSubscription() {
1381 return SubscriptionManager.getDefaultSubId();
1382 }
1383
1384 private long getPreferredVoiceSubscription() {
1385 return SubscriptionManager.getDefaultVoiceSubId();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001386 }
Ihab Awadf2177b72013-11-25 13:33:23 -08001387
1388 /**
1389 * @see android.telephony.TelephonyManager.WifiCallingChoices
1390 */
1391 public int getWhenToMakeWifiCalls() {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001392 return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1393 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
Ihab Awadf2177b72013-11-25 13:33:23 -08001394 }
1395
1396 /**
1397 * @see android.telephony.TelephonyManager.WifiCallingChoices
1398 */
1399 public void setWhenToMakeWifiCalls(int preference) {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001400 if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1401 Settings.System.putInt(mPhone.getContext().getContentResolver(),
1402 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
Ihab Awadf9e92732013-12-05 18:02:52 -08001403 }
1404
Sailesh Nepald1e68152013-12-12 19:08:02 -08001405 private static int getWhenToMakeWifiCallsDefaultPreference() {
1406 // TODO(sail): Use a build property to choose this value.
Evan Charlton9829e882013-12-19 15:30:38 -08001407 return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
Ihab Awadf2177b72013-11-25 13:33:23 -08001408 }
Shishir Agrawal69f68122013-12-16 17:25:49 -08001409
Shishir Agrawal566b7612013-10-28 14:41:00 -07001410 @Override
1411 public int iccOpenLogicalChannel(String AID) {
Junda Liua2e36012014-07-09 18:30:01 -07001412 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001413
1414 if (DBG) log("iccOpenLogicalChannel: " + AID);
1415 Integer channel = (Integer)sendRequest(CMD_OPEN_CHANNEL, AID);
1416 if (DBG) log("iccOpenLogicalChannel: " + channel);
Jake Hambye994d462014-02-03 13:10:13 -08001417 return channel;
Shishir Agrawal566b7612013-10-28 14:41:00 -07001418 }
1419
1420 @Override
1421 public boolean iccCloseLogicalChannel(int channel) {
Junda Liua2e36012014-07-09 18:30:01 -07001422 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001423
1424 if (DBG) log("iccCloseLogicalChannel: " + channel);
1425 if (channel < 0) {
1426 return false;
1427 }
Jake Hambye994d462014-02-03 13:10:13 -08001428 Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
Shishir Agrawal566b7612013-10-28 14:41:00 -07001429 if (DBG) log("iccCloseLogicalChannel: " + success);
1430 return success;
1431 }
1432
1433 @Override
1434 public String iccTransmitApduLogicalChannel(int channel, int cla,
1435 int command, int p1, int p2, int p3, String data) {
Junda Liua2e36012014-07-09 18:30:01 -07001436 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001437
1438 if (DBG) {
1439 log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1440 " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1441 " data=" + data);
1442 }
1443
1444 if (channel < 0) {
1445 return "";
1446 }
1447
1448 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU,
1449 new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1450 if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1451
1452 // If the payload is null, there was an error. Indicate that by returning
1453 // an empty string.
1454 if (response.payload == null) {
1455 return "";
1456 }
1457
1458 // Append the returned status code to the end of the response payload.
1459 String s = Integer.toHexString(
1460 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1461 s = IccUtils.bytesToHexString(response.payload) + s;
1462 return s;
1463 }
Jake Hambye994d462014-02-03 13:10:13 -08001464
Evan Charltonc66da362014-05-16 14:06:40 -07001465 @Override
1466 public String sendEnvelopeWithStatus(String content) {
Junda Liua2e36012014-07-09 18:30:01 -07001467 enforceModifyPermissionOrCarrierPrivilege();
Evan Charltonc66da362014-05-16 14:06:40 -07001468
1469 IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
1470 if (response.payload == null) {
1471 return "";
1472 }
1473
1474 // Append the returned status code to the end of the response payload.
1475 String s = Integer.toHexString(
1476 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1477 s = IccUtils.bytesToHexString(response.payload) + s;
1478 return s;
1479 }
1480
Jake Hambye994d462014-02-03 13:10:13 -08001481 /**
1482 * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1483 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1484 *
1485 * @param itemID the ID of the item to read
1486 * @return the NV item as a String, or null on error.
1487 */
1488 @Override
1489 public String nvReadItem(int itemID) {
Junda Liua2e36012014-07-09 18:30:01 -07001490 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001491 if (DBG) log("nvReadItem: item " + itemID);
1492 String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
1493 if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
1494 return value;
1495 }
1496
1497 /**
1498 * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1499 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1500 *
1501 * @param itemID the ID of the item to read
1502 * @param itemValue the value to write, as a String
1503 * @return true on success; false on any failure
1504 */
1505 @Override
1506 public boolean nvWriteItem(int itemID, String itemValue) {
Junda Liua2e36012014-07-09 18:30:01 -07001507 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001508 if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
1509 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
1510 new Pair<Integer, String>(itemID, itemValue));
1511 if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
1512 return success;
1513 }
1514
1515 /**
1516 * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
1517 * Used for device configuration by some CDMA operators.
1518 *
1519 * @param preferredRoamingList byte array containing the new PRL
1520 * @return true on success; false on any failure
1521 */
1522 @Override
1523 public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
Junda Liua2e36012014-07-09 18:30:01 -07001524 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001525 if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
1526 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
1527 if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
1528 return success;
1529 }
1530
1531 /**
1532 * Perform the specified type of NV config reset.
1533 * Used for device configuration by some CDMA operators.
1534 *
1535 * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
1536 * @return true on success; false on any failure
1537 */
1538 @Override
1539 public boolean nvResetConfig(int resetType) {
Junda Liua2e36012014-07-09 18:30:01 -07001540 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001541 if (DBG) log("nvResetConfig: type " + resetType);
1542 Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
1543 if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
1544 return success;
1545 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001546
1547 /**
Wink Saville36469e72014-06-11 15:17:00 -07001548 * {@hide}
1549 * Returns Default sim, 0 in the case of single standby.
1550 */
1551 public int getDefaultSim() {
1552 //TODO Need to get it from Telephony Devcontroller
1553 return 0;
1554 }
1555
1556 public String[] getPcscfAddress() {
1557 enforceReadPermission();
1558 return mPhone.getPcscfAddress();
1559 }
1560
1561 public void setImsRegistrationState(boolean registered) {
1562 enforceModifyPermission();
1563 mPhone.setImsRegistrationState(registered);
1564 }
1565
1566 /**
Junda Liu84d15a22014-07-02 11:21:04 -07001567 * Get the calculated preferred network type.
1568 * Used for debugging incorrect network type.
1569 *
1570 * @return the preferred network type, defined in RILConstants.java.
1571 */
1572 @Override
1573 public int getCalculatedPreferredNetworkType() {
1574 enforceReadPermission();
1575 return PhoneFactory.calculatePreferredNetworkType(mPhone.getContext());
1576 }
1577
1578 /**
Jake Hamby7c27be32014-03-03 13:25:59 -08001579 * Get the preferred network type.
1580 * Used for device configuration by some CDMA operators.
1581 *
1582 * @return the preferred network type, defined in RILConstants.java.
1583 */
1584 @Override
1585 public int getPreferredNetworkType() {
Junda Liua2e36012014-07-09 18:30:01 -07001586 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001587 if (DBG) log("getPreferredNetworkType");
1588 int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null);
1589 int networkType = (result != null ? result[0] : -1);
1590 if (DBG) log("getPreferredNetworkType: " + networkType);
1591 return networkType;
1592 }
1593
1594 /**
1595 * Set the preferred network type.
1596 * Used for device configuration by some CDMA operators.
1597 *
1598 * @param networkType the preferred network type, defined in RILConstants.java.
1599 * @return true on success; false on any failure.
1600 */
1601 @Override
1602 public boolean setPreferredNetworkType(int networkType) {
Junda Liua2e36012014-07-09 18:30:01 -07001603 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001604 if (DBG) log("setPreferredNetworkType: type " + networkType);
1605 Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType);
1606 if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
1607 return success;
1608 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001609
1610 /**
Junda Liu787bc7e2014-06-30 13:38:02 -07001611 * Set the CDMA subscription source.
1612 * Used for device supporting both NV and RUIM for CDMA.
1613 *
1614 * @param subscriptionType the subscription type, 0 for RUIM, 1 for NV.
1615 * @return true on success; false on any failure.
1616 */
1617 @Override
1618 public boolean setCdmaSubscription(int subscriptionType) {
Junda Liua2e36012014-07-09 18:30:01 -07001619 enforceModifyPermissionOrCarrierPrivilege();
Junda Liu787bc7e2014-06-30 13:38:02 -07001620 if (DBG) log("setCdmaSubscription: type " + subscriptionType);
1621 if (subscriptionType != mPhone.CDMA_SUBSCRIPTION_RUIM_SIM &&
1622 subscriptionType != mPhone.CDMA_SUBSCRIPTION_NV) {
1623 loge("setCdmaSubscription: unsupported subscriptionType.");
1624 return false;
1625 }
1626 Boolean success = (Boolean) sendRequest(CMD_SET_CDMA_SUBSCRIPTION, subscriptionType);
1627 if (DBG) log("setCdmaSubscription: " + (success ? "ok" : "fail"));
1628 if (success) {
1629 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1630 Settings.Global.CDMA_SUBSCRIPTION_MODE, subscriptionType);
1631 }
1632 return success;
1633 }
1634
1635 /**
Robert Greenwalted86e582014-05-21 20:03:20 -07001636 * Set mobile data enabled
1637 * Used by the user through settings etc to turn on/off mobile data
1638 *
1639 * @param enable {@code true} turn turn data on, else {@code false}
1640 */
1641 @Override
1642 public void setDataEnabled(boolean enable) {
1643 enforceModifyPermission();
1644 mPhone.setDataEnabled(enable);
1645 }
1646
1647 /**
Robert Greenwalt646120a2014-05-23 11:54:03 -07001648 * Get whether mobile data is enabled.
1649 *
1650 * Note that this used to be available from ConnectivityService, gated by
1651 * ACCESS_NETWORK_STATE permission, so this will accept either that or
1652 * our MODIFY_PHONE_STATE.
Robert Greenwalted86e582014-05-21 20:03:20 -07001653 *
1654 * @return {@code true} if data is enabled else {@code false}
1655 */
1656 @Override
1657 public boolean getDataEnabled() {
Robert Greenwalt646120a2014-05-23 11:54:03 -07001658 try {
1659 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
1660 null);
1661 } catch (Exception e) {
1662 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
1663 null);
1664 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001665 return mPhone.getDataEnabled();
1666 }
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001667
1668 @Override
1669 public int hasCarrierPrivileges() {
1670 PackageManager packageManager = mPhone.getContext().getPackageManager();
1671 String[] packages = packageManager.getPackagesForUid(Binder.getCallingUid());
1672
1673 for (String pkg : packages) {
1674 try {
1675 PackageInfo pInfo = packageManager.getPackageInfo(pkg,
1676 PackageManager.GET_SIGNATURES);
1677 Signature[] signatures = pInfo.signatures;
1678 for (Signature sig : signatures) {
1679 int hasAccess = UiccController.getInstance().getUiccCard().hasCarrierPrivileges(
1680 sig, pInfo.packageName);
1681 if (hasAccess != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) {
1682 return hasAccess;
1683 }
1684 }
1685 } catch (PackageManager.NameNotFoundException ex) {
1686 loge("NameNotFoundException: " + ex);
1687 continue;
1688 }
1689 }
1690 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
1691 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001692}