blob: 90f2f35db9fe7762d4d6ec7773daf45b37f80657 [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;
Derek Tan7226c842014-07-02 17:42:23 -070062import com.android.internal.telephony.uicc.AdnRecord;
Shishir Agrawal566b7612013-10-28 14:41:00 -070063import com.android.internal.telephony.uicc.IccIoResult;
64import com.android.internal.telephony.uicc.IccUtils;
Shishir Agrawal60f9c952014-06-23 12:00:43 -070065import com.android.internal.telephony.uicc.UiccCarrierPrivilegeRules;
Shishir Agrawal566b7612013-10-28 14:41:00 -070066import com.android.internal.telephony.uicc.UiccController;
Jake Hambye994d462014-02-03 13:10:13 -080067import com.android.internal.util.HexDump;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070068
Wink Saville36469e72014-06-11 15:17:00 -070069import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
70
Santos Cordon7d4ddf62013-07-10 11:58:08 -070071import java.util.ArrayList;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070072import java.util.HashMap;
Derek Tan89e89d42014-07-08 17:00:10 -070073import java.util.HashSet;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070074import java.util.Iterator;
Jake Hambye994d462014-02-03 13:10:13 -080075import java.util.List;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070076import java.util.Map;
Derek Tan89e89d42014-07-08 17:00:10 -070077import java.util.Set;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070078
79/**
80 * Implementation of the ITelephony interface.
81 */
Santos Cordon117fee72014-05-16 17:56:12 -070082public class PhoneInterfaceManager extends ITelephony.Stub {
Santos Cordon7d4ddf62013-07-10 11:58:08 -070083 private static final String LOG_TAG = "PhoneInterfaceManager";
84 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
85 private static final boolean DBG_LOC = false;
86
87 // Message codes used with mMainThreadHandler
88 private static final int CMD_HANDLE_PIN_MMI = 1;
89 private static final int CMD_HANDLE_NEIGHBORING_CELL = 2;
90 private static final int EVENT_NEIGHBORING_CELL_DONE = 3;
91 private static final int CMD_ANSWER_RINGING_CALL = 4;
92 private static final int CMD_END_CALL = 5; // not used yet
93 private static final int CMD_SILENCE_RINGER = 6;
Shishir Agrawal566b7612013-10-28 14:41:00 -070094 private static final int CMD_TRANSMIT_APDU = 7;
95 private static final int EVENT_TRANSMIT_APDU_DONE = 8;
96 private static final int CMD_OPEN_CHANNEL = 9;
97 private static final int EVENT_OPEN_CHANNEL_DONE = 10;
98 private static final int CMD_CLOSE_CHANNEL = 11;
99 private static final int EVENT_CLOSE_CHANNEL_DONE = 12;
Jake Hambye994d462014-02-03 13:10:13 -0800100 private static final int CMD_NV_READ_ITEM = 13;
101 private static final int EVENT_NV_READ_ITEM_DONE = 14;
102 private static final int CMD_NV_WRITE_ITEM = 15;
103 private static final int EVENT_NV_WRITE_ITEM_DONE = 16;
104 private static final int CMD_NV_WRITE_CDMA_PRL = 17;
105 private static final int EVENT_NV_WRITE_CDMA_PRL_DONE = 18;
106 private static final int CMD_NV_RESET_CONFIG = 19;
107 private static final int EVENT_NV_RESET_CONFIG_DONE = 20;
Jake Hamby7c27be32014-03-03 13:25:59 -0800108 private static final int CMD_GET_PREFERRED_NETWORK_TYPE = 21;
109 private static final int EVENT_GET_PREFERRED_NETWORK_TYPE_DONE = 22;
110 private static final int CMD_SET_PREFERRED_NETWORK_TYPE = 23;
111 private static final int EVENT_SET_PREFERRED_NETWORK_TYPE_DONE = 24;
Sailesh Nepal35b59452014-03-06 09:26:56 -0800112 private static final int CMD_SEND_ENVELOPE = 25;
113 private static final int EVENT_SEND_ENVELOPE_DONE = 26;
Junda Liu787bc7e2014-06-30 13:38:02 -0700114 private static final int CMD_SET_CDMA_SUBSCRIPTION = 27;
115 private static final int EVENT_SET_CDMA_SUBSCRIPTION_DONE = 28;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700116
117 /** The singleton instance. */
118 private static PhoneInterfaceManager sInstance;
119
120 PhoneGlobals mApp;
121 Phone mPhone;
122 CallManager mCM;
123 AppOpsManager mAppOps;
124 MainThreadHandler mMainThreadHandler;
125
126 /**
Derek Tan89e89d42014-07-08 17:00:10 -0700127 * Indicates if Android should display a simplified Mobile Network Settings UI in a specific
128 * subscription.
129 */
130 Set<Long> mSimplifiedNetworkSettings;
Derek Tan7226c842014-07-02 17:42:23 -0700131 Map<Long, AdnRecord> mAdnRecordsForDisplay;
Derek Tan89e89d42014-07-08 17:00:10 -0700132
133 /**
Shishir Agrawal566b7612013-10-28 14:41:00 -0700134 * A request object to use for transmitting data to an ICC.
135 */
136 private static final class IccAPDUArgument {
137 public int channel, cla, command, p1, p2, p3;
138 public String data;
139
140 public IccAPDUArgument(int channel, int cla, int command,
141 int p1, int p2, int p3, String data) {
142 this.channel = channel;
143 this.cla = cla;
144 this.command = command;
145 this.p1 = p1;
146 this.p2 = p2;
147 this.p3 = p3;
148 this.data = data;
149 }
150 }
151
152 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700153 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
154 * request after sending. The main thread will notify the request when it is complete.
155 */
156 private static final class MainThreadRequest {
157 /** The argument to use for the request */
158 public Object argument;
159 /** The result of the request that is run on the main thread */
160 public Object result;
161
162 public MainThreadRequest(Object argument) {
163 this.argument = argument;
164 }
165 }
166
Sailesh Nepalcc0375f2013-11-13 09:15:18 -0800167 private static final class IncomingThirdPartyCallArgs {
168 public final ComponentName component;
169 public final String callId;
170 public final String callerDisplayName;
171
172 public IncomingThirdPartyCallArgs(ComponentName component, String callId,
173 String callerDisplayName) {
174 this.component = component;
175 this.callId = callId;
176 this.callerDisplayName = callerDisplayName;
177 }
178 }
179
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700180 /**
181 * A handler that processes messages on the main thread in the phone process. Since many
182 * of the Phone calls are not thread safe this is needed to shuttle the requests from the
183 * inbound binder threads to the main thread in the phone process. The Binder thread
184 * may provide a {@link MainThreadRequest} object in the msg.obj field that they are waiting
185 * on, which will be notified when the operation completes and will contain the result of the
186 * request.
187 *
188 * <p>If a MainThreadRequest object is provided in the msg.obj field,
189 * note that request.result must be set to something non-null for the calling thread to
190 * unblock.
191 */
192 private final class MainThreadHandler extends Handler {
193 @Override
194 public void handleMessage(Message msg) {
195 MainThreadRequest request;
196 Message onCompleted;
197 AsyncResult ar;
198
199 switch (msg.what) {
200 case CMD_HANDLE_PIN_MMI:
201 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800202 request.result = mPhone.handlePinMmi((String) request.argument);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700203 // Wake up the requesting thread
204 synchronized (request) {
205 request.notifyAll();
206 }
207 break;
208
209 case CMD_HANDLE_NEIGHBORING_CELL:
210 request = (MainThreadRequest) msg.obj;
211 onCompleted = obtainMessage(EVENT_NEIGHBORING_CELL_DONE,
212 request);
213 mPhone.getNeighboringCids(onCompleted);
214 break;
215
216 case EVENT_NEIGHBORING_CELL_DONE:
217 ar = (AsyncResult) msg.obj;
218 request = (MainThreadRequest) ar.userObj;
219 if (ar.exception == null && ar.result != null) {
220 request.result = ar.result;
221 } else {
222 // create an empty list to notify the waiting thread
Jake Hambye994d462014-02-03 13:10:13 -0800223 request.result = new ArrayList<NeighboringCellInfo>(0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700224 }
225 // Wake up the requesting thread
226 synchronized (request) {
227 request.notifyAll();
228 }
229 break;
230
231 case CMD_ANSWER_RINGING_CALL:
232 answerRingingCallInternal();
233 break;
234
235 case CMD_SILENCE_RINGER:
236 silenceRingerInternal();
237 break;
238
239 case CMD_END_CALL:
240 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800241 boolean hungUp;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700242 int phoneType = mPhone.getPhoneType();
243 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
244 // CDMA: If the user presses the Power button we treat it as
245 // ending the complete call session
246 hungUp = PhoneUtils.hangupRingingAndActive(mPhone);
247 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
248 // GSM: End the call as per the Phone state
249 hungUp = PhoneUtils.hangup(mCM);
250 } else {
251 throw new IllegalStateException("Unexpected phone type: " + phoneType);
252 }
253 if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up"));
254 request.result = hungUp;
255 // Wake up the requesting thread
256 synchronized (request) {
257 request.notifyAll();
258 }
259 break;
260
Shishir Agrawal566b7612013-10-28 14:41:00 -0700261 case CMD_TRANSMIT_APDU:
262 request = (MainThreadRequest) msg.obj;
263 IccAPDUArgument argument = (IccAPDUArgument) request.argument;
264 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_DONE, request);
265 UiccController.getInstance().getUiccCard().iccTransmitApduLogicalChannel(
266 argument.channel, argument.cla, argument.command,
267 argument.p1, argument.p2, argument.p3, argument.data,
268 onCompleted);
269 break;
270
271 case EVENT_TRANSMIT_APDU_DONE:
272 ar = (AsyncResult) msg.obj;
273 request = (MainThreadRequest) ar.userObj;
274 if (ar.exception == null && ar.result != null) {
275 request.result = ar.result;
276 } else {
277 request.result = new IccIoResult(0x6F, 0, (byte[])null);
278 if (ar.result == null) {
279 loge("iccTransmitApduLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800280 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700281 loge("iccTransmitApduLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800282 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700283 } else {
284 loge("iccTransmitApduLogicalChannel: Unknown exception");
285 }
286 }
287 synchronized (request) {
288 request.notifyAll();
289 }
290 break;
291
Derek Tan4d5e5c12014-02-04 11:54:58 -0800292 case CMD_SEND_ENVELOPE:
293 request = (MainThreadRequest) msg.obj;
294 onCompleted = obtainMessage(EVENT_SEND_ENVELOPE_DONE, request);
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700295 UiccController.getInstance().getUiccCard().sendEnvelopeWithStatus(
Derek Tan4d5e5c12014-02-04 11:54:58 -0800296 (String)request.argument, onCompleted);
297 break;
298
299 case EVENT_SEND_ENVELOPE_DONE:
300 ar = (AsyncResult) msg.obj;
301 request = (MainThreadRequest) ar.userObj;
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700302 if (ar.exception == null && ar.result != null) {
303 request.result = ar.result;
Derek Tan4d5e5c12014-02-04 11:54:58 -0800304 } else {
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700305 request.result = new IccIoResult(0x6F, 0, (byte[])null);
306 if (ar.result == null) {
307 loge("sendEnvelopeWithStatus: Empty response");
308 } else if (ar.exception instanceof CommandException) {
309 loge("sendEnvelopeWithStatus: CommandException: " +
310 ar.exception);
311 } else {
312 loge("sendEnvelopeWithStatus: exception:" + ar.exception);
313 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800314 }
315 synchronized (request) {
316 request.notifyAll();
317 }
318 break;
319
Shishir Agrawal566b7612013-10-28 14:41:00 -0700320 case CMD_OPEN_CHANNEL:
321 request = (MainThreadRequest) msg.obj;
322 onCompleted = obtainMessage(EVENT_OPEN_CHANNEL_DONE, request);
323 UiccController.getInstance().getUiccCard().iccOpenLogicalChannel(
324 (String)request.argument, onCompleted);
325 break;
326
327 case EVENT_OPEN_CHANNEL_DONE:
328 ar = (AsyncResult) msg.obj;
329 request = (MainThreadRequest) ar.userObj;
330 if (ar.exception == null && ar.result != null) {
Jake Hambye994d462014-02-03 13:10:13 -0800331 request.result = ((int[]) ar.result)[0];
Shishir Agrawal566b7612013-10-28 14:41:00 -0700332 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800333 request.result = -1;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700334 if (ar.result == null) {
335 loge("iccOpenLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800336 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700337 loge("iccOpenLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800338 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700339 } else {
340 loge("iccOpenLogicalChannel: Unknown exception");
341 }
342 }
343 synchronized (request) {
344 request.notifyAll();
345 }
346 break;
347
348 case CMD_CLOSE_CHANNEL:
349 request = (MainThreadRequest) msg.obj;
350 onCompleted = obtainMessage(EVENT_CLOSE_CHANNEL_DONE,
351 request);
352 UiccController.getInstance().getUiccCard().iccCloseLogicalChannel(
Jake Hambye994d462014-02-03 13:10:13 -0800353 (Integer) request.argument,
Shishir Agrawal566b7612013-10-28 14:41:00 -0700354 onCompleted);
355 break;
356
357 case EVENT_CLOSE_CHANNEL_DONE:
Jake Hambye994d462014-02-03 13:10:13 -0800358 handleNullReturnEvent(msg, "iccCloseLogicalChannel");
359 break;
360
361 case CMD_NV_READ_ITEM:
362 request = (MainThreadRequest) msg.obj;
363 onCompleted = obtainMessage(EVENT_NV_READ_ITEM_DONE, request);
364 mPhone.nvReadItem((Integer) request.argument, onCompleted);
365 break;
366
367 case EVENT_NV_READ_ITEM_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700368 ar = (AsyncResult) msg.obj;
369 request = (MainThreadRequest) ar.userObj;
Jake Hambye994d462014-02-03 13:10:13 -0800370 if (ar.exception == null && ar.result != null) {
371 request.result = ar.result; // String
Shishir Agrawal566b7612013-10-28 14:41:00 -0700372 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800373 request.result = "";
374 if (ar.result == null) {
375 loge("nvReadItem: Empty response");
376 } else if (ar.exception instanceof CommandException) {
377 loge("nvReadItem: CommandException: " +
378 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700379 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800380 loge("nvReadItem: Unknown exception");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700381 }
382 }
383 synchronized (request) {
384 request.notifyAll();
385 }
386 break;
387
Jake Hambye994d462014-02-03 13:10:13 -0800388 case CMD_NV_WRITE_ITEM:
389 request = (MainThreadRequest) msg.obj;
390 onCompleted = obtainMessage(EVENT_NV_WRITE_ITEM_DONE, request);
391 Pair<Integer, String> idValue = (Pair<Integer, String>) request.argument;
392 mPhone.nvWriteItem(idValue.first, idValue.second, onCompleted);
393 break;
394
395 case EVENT_NV_WRITE_ITEM_DONE:
396 handleNullReturnEvent(msg, "nvWriteItem");
397 break;
398
399 case CMD_NV_WRITE_CDMA_PRL:
400 request = (MainThreadRequest) msg.obj;
401 onCompleted = obtainMessage(EVENT_NV_WRITE_CDMA_PRL_DONE, request);
402 mPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
403 break;
404
405 case EVENT_NV_WRITE_CDMA_PRL_DONE:
406 handleNullReturnEvent(msg, "nvWriteCdmaPrl");
407 break;
408
409 case CMD_NV_RESET_CONFIG:
410 request = (MainThreadRequest) msg.obj;
411 onCompleted = obtainMessage(EVENT_NV_RESET_CONFIG_DONE, request);
412 mPhone.nvResetConfig((Integer) request.argument, onCompleted);
413 break;
414
415 case EVENT_NV_RESET_CONFIG_DONE:
416 handleNullReturnEvent(msg, "nvResetConfig");
417 break;
418
Jake Hamby7c27be32014-03-03 13:25:59 -0800419 case CMD_GET_PREFERRED_NETWORK_TYPE:
420 request = (MainThreadRequest) msg.obj;
421 onCompleted = obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE_DONE, request);
422 mPhone.getPreferredNetworkType(onCompleted);
423 break;
424
425 case EVENT_GET_PREFERRED_NETWORK_TYPE_DONE:
426 ar = (AsyncResult) msg.obj;
427 request = (MainThreadRequest) ar.userObj;
428 if (ar.exception == null && ar.result != null) {
429 request.result = ar.result; // Integer
430 } else {
431 request.result = -1;
432 if (ar.result == null) {
433 loge("getPreferredNetworkType: Empty response");
434 } else if (ar.exception instanceof CommandException) {
435 loge("getPreferredNetworkType: CommandException: " +
436 ar.exception);
437 } else {
438 loge("getPreferredNetworkType: Unknown exception");
439 }
440 }
441 synchronized (request) {
442 request.notifyAll();
443 }
444 break;
445
446 case CMD_SET_PREFERRED_NETWORK_TYPE:
447 request = (MainThreadRequest) msg.obj;
448 onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);
449 int networkType = (Integer) request.argument;
450 mPhone.setPreferredNetworkType(networkType, onCompleted);
451 break;
452
453 case EVENT_SET_PREFERRED_NETWORK_TYPE_DONE:
454 handleNullReturnEvent(msg, "setPreferredNetworkType");
455 break;
456
Junda Liu787bc7e2014-06-30 13:38:02 -0700457 case CMD_SET_CDMA_SUBSCRIPTION:
458 request = (MainThreadRequest) msg.obj;
459 onCompleted = obtainMessage(EVENT_SET_CDMA_SUBSCRIPTION_DONE, request);
460 int subscriptionType = (Integer) request.argument;
461 mPhone.setCdmaSubscription(subscriptionType, onCompleted);
462 break;
463
464 case EVENT_SET_CDMA_SUBSCRIPTION_DONE:
465 handleNullReturnEvent(msg, "setCdmaSubscription");
466 break;
467
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700468 default:
469 Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
470 break;
471 }
472 }
Jake Hambye994d462014-02-03 13:10:13 -0800473
474 private void handleNullReturnEvent(Message msg, String command) {
475 AsyncResult ar = (AsyncResult) msg.obj;
476 MainThreadRequest request = (MainThreadRequest) ar.userObj;
477 if (ar.exception == null) {
478 request.result = true;
479 } else {
480 request.result = false;
481 if (ar.exception instanceof CommandException) {
482 loge(command + ": CommandException: " + ar.exception);
483 } else {
484 loge(command + ": Unknown exception");
485 }
486 }
487 synchronized (request) {
488 request.notifyAll();
489 }
490 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700491 }
492
493 /**
494 * Posts the specified command to be executed on the main thread,
495 * waits for the request to complete, and returns the result.
496 * @see #sendRequestAsync
497 */
498 private Object sendRequest(int command, Object argument) {
Santos Cordon500b0e02014-06-17 10:33:33 -0700499 return sendRequest(command, argument, null);
Wink Saville36469e72014-06-11 15:17:00 -0700500 }
501
502 /**
503 * Posts the specified command to be executed on the main thread,
504 * waits for the request to complete, and returns the result.
505 * @see #sendRequestAsync
506 */
507 private Object sendRequest(int command, Object argument, Object argument2) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700508 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
509 throw new RuntimeException("This method will deadlock if called from the main thread.");
510 }
511
512 MainThreadRequest request = new MainThreadRequest(argument);
513 Message msg = mMainThreadHandler.obtainMessage(command, request);
514 msg.sendToTarget();
515
516 // Wait for the request to complete
517 synchronized (request) {
518 while (request.result == null) {
519 try {
520 request.wait();
521 } catch (InterruptedException e) {
522 // Do nothing, go back and wait until the request is complete
523 }
524 }
525 }
526 return request.result;
527 }
528
529 /**
530 * Asynchronous ("fire and forget") version of sendRequest():
531 * Posts the specified command to be executed on the main thread, and
532 * returns immediately.
533 * @see #sendRequest
534 */
535 private void sendRequestAsync(int command) {
536 mMainThreadHandler.sendEmptyMessage(command);
537 }
538
539 /**
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -0700540 * Same as {@link #sendRequestAsync(int)} except it takes an argument.
541 * @see {@link #sendRequest(int,Object)}
542 */
543 private void sendRequestAsync(int command, Object argument) {
544 MainThreadRequest request = new MainThreadRequest(argument);
545 Message msg = mMainThreadHandler.obtainMessage(command, request);
546 msg.sendToTarget();
547 }
548
549 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700550 * Initialize the singleton PhoneInterfaceManager instance.
551 * This is only done once, at startup, from PhoneApp.onCreate().
552 */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700553 /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700554 synchronized (PhoneInterfaceManager.class) {
555 if (sInstance == null) {
Sailesh Nepal194161e2014-07-03 08:57:44 -0700556 sInstance = new PhoneInterfaceManager(app, phone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700557 } else {
558 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
559 }
560 return sInstance;
561 }
562 }
563
564 /** Private constructor; @see init() */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700565 private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700566 mApp = app;
567 mPhone = phone;
568 mCM = PhoneGlobals.getInstance().mCM;
Derek Tan89e89d42014-07-08 17:00:10 -0700569 mSimplifiedNetworkSettings = new HashSet<Long>();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700570 mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
571 mMainThreadHandler = new MainThreadHandler();
Derek Tan7226c842014-07-02 17:42:23 -0700572 mAdnRecordsForDisplay = new HashMap<Long, AdnRecord>();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700573 publish();
574 }
575
576 private void publish() {
577 if (DBG) log("publish: " + this);
578
579 ServiceManager.addService("phone", this);
580 }
581
Wink Saville36469e72014-06-11 15:17:00 -0700582 // returns phone associated with the subId.
583 // getPhone(0) returns default phone in single SIM mode.
584 private Phone getPhone(long subId) {
585 // FIXME: hack for the moment
586 return mPhone;
587 // return PhoneUtils.getPhoneUsingSubId(subId);
588 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700589 //
590 // Implementation of the ITelephony interface.
591 //
592
593 public void dial(String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700594 dialUsingSubId(getPreferredVoiceSubscription(), number);
595 }
596
597 public void dialUsingSubId(long subId, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700598 if (DBG) log("dial: " + number);
599 // No permission check needed here: This is just a wrapper around the
600 // ACTION_DIAL intent, which is available to any app since it puts up
601 // the UI before it does anything.
602
603 String url = createTelUrl(number);
604 if (url == null) {
605 return;
606 }
607
608 // PENDING: should we just silently fail if phone is offhook or ringing?
Wink Saville36469e72014-06-11 15:17:00 -0700609 PhoneConstants.State state = mCM.getState(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700610 if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
611 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
612 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Wink Saville36469e72014-06-11 15:17:00 -0700613 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700614 mApp.startActivity(intent);
615 }
616 }
617
618 public void call(String callingPackage, String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700619 callUsingSubId(getPreferredVoiceSubscription(), callingPackage, number);
620 }
621
622 public void callUsingSubId(long subId, String callingPackage, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700623 if (DBG) log("call: " + number);
624
625 // This is just a wrapper around the ACTION_CALL intent, but we still
626 // need to do a permission check since we're calling startActivity()
627 // from the context of the phone app.
628 enforceCallPermission();
629
630 if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
631 != AppOpsManager.MODE_ALLOWED) {
632 return;
633 }
634
635 String url = createTelUrl(number);
636 if (url == null) {
637 return;
638 }
639
640 Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
Wink Saville36469e72014-06-11 15:17:00 -0700641 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700642 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
643 mApp.startActivity(intent);
644 }
645
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700646 /**
647 * End a call based on call state
648 * @return true is a call was ended
649 */
650 public boolean endCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700651 return endCallUsingSubId(getDefaultSubscription());
652 }
653
654 /**
655 * End a call based on the call state of the subId
656 * @return true is a call was ended
657 */
658 public boolean endCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700659 enforceCallPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700660 return (Boolean) sendRequest(CMD_END_CALL, subId, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700661 }
662
663 public void answerRingingCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700664 answerRingingCallUsingSubId(getDefaultSubscription());
665 }
666
667 public void answerRingingCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700668 if (DBG) log("answerRingingCall...");
669 // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
670 // but that can probably wait till the big TelephonyManager API overhaul.
671 // For now, protect this call with the MODIFY_PHONE_STATE permission.
672 enforceModifyPermission();
673 sendRequestAsync(CMD_ANSWER_RINGING_CALL);
674 }
675
676 /**
677 * Make the actual telephony calls to implement answerRingingCall().
678 * This should only be called from the main thread of the Phone app.
679 * @see #answerRingingCall
680 *
681 * TODO: it would be nice to return true if we answered the call, or
682 * false if there wasn't actually a ringing incoming call, or some
683 * other error occurred. (In other words, pass back the return value
684 * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
685 * But that would require calling this method via sendRequest() rather
686 * than sendRequestAsync(), and right now we don't actually *need* that
687 * return value, so let's just return void for now.
688 */
689 private void answerRingingCallInternal() {
690 final boolean hasRingingCall = !mPhone.getRingingCall().isIdle();
691 if (hasRingingCall) {
692 final boolean hasActiveCall = !mPhone.getForegroundCall().isIdle();
693 final boolean hasHoldingCall = !mPhone.getBackgroundCall().isIdle();
694 if (hasActiveCall && hasHoldingCall) {
695 // Both lines are in use!
696 // TODO: provide a flag to let the caller specify what
697 // policy to use if both lines are in use. (The current
698 // behavior is hardwired to "answer incoming, end ongoing",
699 // which is how the CALL button is specced to behave.)
700 PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
701 return;
702 } else {
703 // answerCall() will automatically hold the current active
704 // call, if there is one.
705 PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
706 return;
707 }
708 } else {
709 // No call was ringing.
710 return;
711 }
712 }
713
714 public void silenceRinger() {
715 if (DBG) log("silenceRinger...");
716 // TODO: find a more appropriate permission to check here.
717 // (That can probably wait till the big TelephonyManager API overhaul.
718 // For now, protect this call with the MODIFY_PHONE_STATE permission.)
719 enforceModifyPermission();
720 sendRequestAsync(CMD_SILENCE_RINGER);
721 }
722
723 /**
724 * Internal implemenation of silenceRinger().
725 * This should only be called from the main thread of the Phone app.
726 * @see #silenceRinger
727 */
728 private void silenceRingerInternal() {
729 if ((mCM.getState() == PhoneConstants.State.RINGING)
730 && mApp.notifier.isRinging()) {
731 // Ringer is actually playing, so silence it.
732 if (DBG) log("silenceRingerInternal: silencing...");
733 mApp.notifier.silenceRinger();
734 }
735 }
736
737 public boolean isOffhook() {
Wink Saville36469e72014-06-11 15:17:00 -0700738 return isOffhookUsingSubId(getDefaultSubscription());
739 }
740
741 public boolean isOffhookUsingSubId(long subId) {
742 return (getPhone(subId).getState() == PhoneConstants.State.OFFHOOK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700743 }
744
745 public boolean isRinging() {
Wink Saville36469e72014-06-11 15:17:00 -0700746 return (isRingingUsingSubId(getDefaultSubscription()));
747 }
748
749 public boolean isRingingUsingSubId(long subId) {
750 return (getPhone(subId).getState() == PhoneConstants.State.RINGING);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700751 }
752
753 public boolean isIdle() {
Wink Saville36469e72014-06-11 15:17:00 -0700754 return isIdleUsingSubId(getDefaultSubscription());
755 }
756
757 public boolean isIdleUsingSubId(long subId) {
758 return (getPhone(subId).getState() == PhoneConstants.State.IDLE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700759 }
760
761 public boolean isSimPinEnabled() {
762 enforceReadPermission();
763 return (PhoneGlobals.getInstance().isSimPinEnabled());
764 }
765
766 public boolean supplyPin(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700767 return supplyPinUsingSubId(getDefaultSubscription(), pin);
768 }
769
770 public boolean supplyPinUsingSubId(long subId, String pin) {
771 int [] resultArray = supplyPinReportResultUsingSubId(subId, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700772 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
773 }
774
775 public boolean supplyPuk(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700776 return supplyPukUsingSubId(getDefaultSubscription(), puk, pin);
777 }
778
779 public boolean supplyPukUsingSubId(long subId, String puk, String pin) {
780 int [] resultArray = supplyPukReportResultUsingSubId(subId, puk, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700781 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
782 }
783
784 /** {@hide} */
785 public int[] supplyPinReportResult(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700786 return supplyPinReportResultUsingSubId(getDefaultSubscription(), pin);
787 }
788
789 public int[] supplyPinReportResultUsingSubId(long subId, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700790 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700791 final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700792 checkSimPin.start();
793 return checkSimPin.unlockSim(null, pin);
794 }
795
Wink Saville9de0f752013-10-22 19:04:03 -0700796 /** {@hide} */
797 public int[] supplyPukReportResult(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700798 return supplyPukReportResultUsingSubId(getDefaultSubscription(), puk, pin);
799 }
800
801 public int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700802 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700803 final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700804 checkSimPuk.start();
805 return checkSimPuk.unlockSim(puk, pin);
806 }
807
808 /**
Wink Saville9de0f752013-10-22 19:04:03 -0700809 * Helper thread to turn async call to SimCard#supplyPin into
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700810 * a synchronous one.
811 */
812 private static class UnlockSim extends Thread {
813
814 private final IccCard mSimCard;
815
816 private boolean mDone = false;
Wink Saville9de0f752013-10-22 19:04:03 -0700817 private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
818 private int mRetryCount = -1;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700819
820 // For replies from SimCard interface
821 private Handler mHandler;
822
823 // For async handler to identify request type
824 private static final int SUPPLY_PIN_COMPLETE = 100;
825
826 public UnlockSim(IccCard simCard) {
827 mSimCard = simCard;
828 }
829
830 @Override
831 public void run() {
832 Looper.prepare();
833 synchronized (UnlockSim.this) {
834 mHandler = new Handler() {
835 @Override
836 public void handleMessage(Message msg) {
837 AsyncResult ar = (AsyncResult) msg.obj;
838 switch (msg.what) {
839 case SUPPLY_PIN_COMPLETE:
840 Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
841 synchronized (UnlockSim.this) {
Wink Saville9de0f752013-10-22 19:04:03 -0700842 mRetryCount = msg.arg1;
843 if (ar.exception != null) {
844 if (ar.exception instanceof CommandException &&
845 ((CommandException)(ar.exception)).getCommandError()
846 == CommandException.Error.PASSWORD_INCORRECT) {
847 mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
848 } else {
849 mResult = PhoneConstants.PIN_GENERAL_FAILURE;
850 }
851 } else {
852 mResult = PhoneConstants.PIN_RESULT_SUCCESS;
853 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700854 mDone = true;
855 UnlockSim.this.notifyAll();
856 }
857 break;
858 }
859 }
860 };
861 UnlockSim.this.notifyAll();
862 }
863 Looper.loop();
864 }
865
866 /*
867 * Use PIN or PUK to unlock SIM card
868 *
869 * If PUK is null, unlock SIM card with PIN
870 *
871 * If PUK is not null, unlock SIM card with PUK and set PIN code
872 */
Wink Saville9de0f752013-10-22 19:04:03 -0700873 synchronized int[] unlockSim(String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700874
875 while (mHandler == null) {
876 try {
877 wait();
878 } catch (InterruptedException e) {
879 Thread.currentThread().interrupt();
880 }
881 }
882 Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
883
884 if (puk == null) {
885 mSimCard.supplyPin(pin, callback);
886 } else {
887 mSimCard.supplyPuk(puk, pin, callback);
888 }
889
890 while (!mDone) {
891 try {
892 Log.d(LOG_TAG, "wait for done");
893 wait();
894 } catch (InterruptedException e) {
895 // Restore the interrupted status
896 Thread.currentThread().interrupt();
897 }
898 }
899 Log.d(LOG_TAG, "done");
Wink Saville9de0f752013-10-22 19:04:03 -0700900 int[] resultArray = new int[2];
901 resultArray[0] = mResult;
902 resultArray[1] = mRetryCount;
903 return resultArray;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700904 }
905 }
906
907 public void updateServiceLocation() {
Wink Saville36469e72014-06-11 15:17:00 -0700908 updateServiceLocationUsingSubId(getDefaultSubscription());
909
910 }
911
912 public void updateServiceLocationUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700913 // No permission check needed here: this call is harmless, and it's
914 // needed for the ServiceState.requestStateUpdate() call (which is
915 // already intentionally exposed to 3rd parties.)
Wink Saville36469e72014-06-11 15:17:00 -0700916 getPhone(subId).updateServiceLocation();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700917 }
918
919 public boolean isRadioOn() {
Wink Saville36469e72014-06-11 15:17:00 -0700920 return isRadioOnUsingSubId(getDefaultSubscription());
921 }
922
923 public boolean isRadioOnUsingSubId(long subId) {
924 return getPhone(subId).getServiceState().getState() != ServiceState.STATE_POWER_OFF;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700925 }
926
927 public void toggleRadioOnOff() {
Wink Saville36469e72014-06-11 15:17:00 -0700928 toggleRadioOnOffUsingSubId(getDefaultSubscription());
929
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700930 }
Wink Saville36469e72014-06-11 15:17:00 -0700931
932 public void toggleRadioOnOffUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700933 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700934 getPhone(subId).setRadioPower(!isRadioOnUsingSubId(subId));
935 }
936
937 public boolean setRadio(boolean turnOn) {
938 return setRadioUsingSubId(getDefaultSubscription(), turnOn);
939 }
940
941 public boolean setRadioUsingSubId(long subId, boolean turnOn) {
942 enforceModifyPermission();
943 if ((getPhone(subId).getServiceState().getState() !=
944 ServiceState.STATE_POWER_OFF) != turnOn) {
945 toggleRadioOnOffUsingSubId(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700946 }
947 return true;
948 }
Wink Saville36469e72014-06-11 15:17:00 -0700949
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700950 public boolean setRadioPower(boolean turnOn) {
Wink Saville36469e72014-06-11 15:17:00 -0700951 return setRadioPowerUsingSubId(getDefaultSubscription(), turnOn);
952 }
953
954 public boolean setRadioPowerUsingSubId(long subId, boolean turnOn) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700955 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700956 getPhone(subId).setRadioPower(turnOn);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700957 return true;
958 }
959
Wink Saville36469e72014-06-11 15:17:00 -0700960 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700961 public boolean enableDataConnectivity() {
962 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700963 long subId = SubscriptionManager.getDefaultDataSubId();
964 getPhone(subId).setDataEnabled(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700965 return true;
966 }
967
Wink Saville36469e72014-06-11 15:17:00 -0700968 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700969 public boolean disableDataConnectivity() {
970 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700971 long subId = SubscriptionManager.getDefaultDataSubId();
972 getPhone(subId).setDataEnabled(false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700973 return true;
974 }
975
Wink Saville36469e72014-06-11 15:17:00 -0700976 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700977 public boolean isDataConnectivityPossible() {
Wink Saville36469e72014-06-11 15:17:00 -0700978 long subId = SubscriptionManager.getDefaultDataSubId();
979 return getPhone(subId).isDataConnectivityPossible();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700980 }
981
982 public boolean handlePinMmi(String dialString) {
Wink Saville36469e72014-06-11 15:17:00 -0700983 return handlePinMmiUsingSubId(getDefaultSubscription(), dialString);
984 }
985
986 public boolean handlePinMmiUsingSubId(long subId, String dialString) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700987 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700988 return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700989 }
990
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700991 public int getCallState() {
Wink Saville36469e72014-06-11 15:17:00 -0700992 return getCallStateUsingSubId(getDefaultSubscription());
993 }
994
995 public int getCallStateUsingSubId(long subId) {
996 return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700997 }
998
999 public int getDataState() {
Wink Saville36469e72014-06-11 15:17:00 -07001000 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1001 return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001002 }
1003
1004 public int getDataActivity() {
Wink Saville36469e72014-06-11 15:17:00 -07001005 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1006 return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001007 }
1008
1009 @Override
1010 public Bundle getCellLocation() {
1011 try {
1012 mApp.enforceCallingOrSelfPermission(
1013 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1014 } catch (SecurityException e) {
1015 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1016 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1017 // is the weaker precondition
1018 mApp.enforceCallingOrSelfPermission(
1019 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1020 }
1021
Jake Hambye994d462014-02-03 13:10:13 -08001022 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001023 if (DBG_LOC) log("getCellLocation: is active user");
1024 Bundle data = new Bundle();
1025 mPhone.getCellLocation().fillInNotifierBundle(data);
1026 return data;
1027 } else {
1028 if (DBG_LOC) log("getCellLocation: suppress non-active user");
1029 return null;
1030 }
1031 }
1032
1033 @Override
1034 public void enableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001035 enableLocationUpdatesUsingSubId(getDefaultSubscription());
1036 }
1037
1038 public void enableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001039 mApp.enforceCallingOrSelfPermission(
1040 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001041 getPhone(subId).enableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001042 }
1043
1044 @Override
1045 public void disableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001046 disableLocationUpdatesUsingSubId(getDefaultSubscription());
1047 }
1048
1049 public void disableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001050 mApp.enforceCallingOrSelfPermission(
1051 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001052 getPhone(subId).disableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001053 }
1054
1055 @Override
1056 @SuppressWarnings("unchecked")
1057 public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1058 try {
1059 mApp.enforceCallingOrSelfPermission(
1060 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1061 } catch (SecurityException e) {
1062 // If we have ACCESS_FINE_LOCATION permission, skip the check
1063 // for ACCESS_COARSE_LOCATION
1064 // A failure should throw the SecurityException from
1065 // ACCESS_COARSE_LOCATION since this is the weaker precondition
1066 mApp.enforceCallingOrSelfPermission(
1067 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1068 }
1069
1070 if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1071 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1072 return null;
1073 }
Jake Hambye994d462014-02-03 13:10:13 -08001074 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001075 if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1076
1077 ArrayList<NeighboringCellInfo> cells = null;
1078
1079 try {
1080 cells = (ArrayList<NeighboringCellInfo>) sendRequest(
Wink Saville36469e72014-06-11 15:17:00 -07001081 CMD_HANDLE_NEIGHBORING_CELL, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001082 } catch (RuntimeException e) {
Wink Saville36469e72014-06-11 15:17:00 -07001083 Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001084 }
1085 return cells;
1086 } else {
1087 if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1088 return null;
1089 }
1090 }
1091
1092
1093 @Override
1094 public List<CellInfo> getAllCellInfo() {
1095 try {
1096 mApp.enforceCallingOrSelfPermission(
1097 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1098 } catch (SecurityException e) {
1099 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1100 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1101 // is the weaker precondition
1102 mApp.enforceCallingOrSelfPermission(
1103 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1104 }
1105
Jake Hambye994d462014-02-03 13:10:13 -08001106 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001107 if (DBG_LOC) log("getAllCellInfo: is active user");
1108 return mPhone.getAllCellInfo();
1109 } else {
1110 if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1111 return null;
1112 }
1113 }
1114
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -07001115 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001116 public void setCellInfoListRate(int rateInMillis) {
1117 mPhone.setCellInfoListRate(rateInMillis);
1118 }
1119
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001120 //
1121 // Internal helper methods.
1122 //
1123
Jake Hambye994d462014-02-03 13:10:13 -08001124 private static boolean checkIfCallerIsSelfOrForegroundUser() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001125 boolean ok;
1126
1127 boolean self = Binder.getCallingUid() == Process.myUid();
1128 if (!self) {
1129 // Get the caller's user id then clear the calling identity
1130 // which will be restored in the finally clause.
1131 int callingUser = UserHandle.getCallingUserId();
1132 long ident = Binder.clearCallingIdentity();
1133
1134 try {
1135 // With calling identity cleared the current user is the foreground user.
1136 int foregroundUser = ActivityManager.getCurrentUser();
1137 ok = (foregroundUser == callingUser);
1138 if (DBG_LOC) {
1139 log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1140 + " callingUser=" + callingUser + " ok=" + ok);
1141 }
1142 } catch (Exception ex) {
1143 if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1144 ok = false;
1145 } finally {
1146 Binder.restoreCallingIdentity(ident);
1147 }
1148 } else {
1149 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1150 ok = true;
1151 }
1152 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1153 return ok;
1154 }
1155
1156 /**
1157 * Make sure the caller has the READ_PHONE_STATE permission.
1158 *
1159 * @throws SecurityException if the caller does not have the required permission
1160 */
1161 private void enforceReadPermission() {
1162 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
1163 }
1164
1165 /**
1166 * Make sure the caller has the MODIFY_PHONE_STATE permission.
1167 *
1168 * @throws SecurityException if the caller does not have the required permission
1169 */
1170 private void enforceModifyPermission() {
1171 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1172 }
1173
1174 /**
Junda Liua2e36012014-07-09 18:30:01 -07001175 * Make sure either system app or the caller has carrier privilege.
1176 *
1177 * @throws SecurityException if the caller does not have the required permission/privilege
1178 */
1179 private void enforceModifyPermissionOrCarrierPrivilege() {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001180 int permission = mApp.checkCallingOrSelfPermission(
1181 android.Manifest.permission.MODIFY_PHONE_STATE);
1182 if (permission == PackageManager.PERMISSION_GRANTED) {
1183 return;
1184 }
1185
1186 log("No modify permission, check carrier privilege next.");
1187 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1188 loge("No Carrier Privilege.");
1189 throw new SecurityException("No modify permission or carrier privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001190 }
1191 }
1192
1193 /**
1194 * Make sure the caller has carrier privilege.
1195 *
1196 * @throws SecurityException if the caller does not have the required permission
1197 */
1198 private void enforceCarrierPrivilege() {
1199 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001200 loge("No Carrier Privilege.");
1201 throw new SecurityException("No Carrier Privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001202 }
1203 }
1204
1205 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001206 * Make sure the caller has the CALL_PHONE permission.
1207 *
1208 * @throws SecurityException if the caller does not have the required permission
1209 */
1210 private void enforceCallPermission() {
1211 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1212 }
1213
Shishir Agrawal566b7612013-10-28 14:41:00 -07001214 /**
Gabriel Peal36ebb0d2014-03-20 09:20:43 -07001215 * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1216 *
1217 * @throws SecurityException if the caller does not have the required permission
1218 */
1219 private void enforcePrivilegedPhoneStatePermission() {
1220 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1221 null);
1222 }
1223
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001224 private String createTelUrl(String number) {
1225 if (TextUtils.isEmpty(number)) {
1226 return null;
1227 }
1228
Jake Hambye994d462014-02-03 13:10:13 -08001229 return "tel:" + number;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001230 }
1231
Ihab Awadf9e92732013-12-05 18:02:52 -08001232 private static void log(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001233 Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1234 }
1235
Ihab Awadf9e92732013-12-05 18:02:52 -08001236 private static void loge(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001237 Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1238 }
1239
1240 public int getActivePhoneType() {
Wink Saville36469e72014-06-11 15:17:00 -07001241 return getActivePhoneTypeUsingSubId(getDefaultSubscription());
1242 }
1243
1244 public int getActivePhoneTypeUsingSubId(long subId) {
1245 return getPhone(subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001246 }
1247
1248 /**
1249 * Returns the CDMA ERI icon index to display
1250 */
1251 public int getCdmaEriIconIndex() {
Wink Saville36469e72014-06-11 15:17:00 -07001252 return getCdmaEriIconIndexUsingSubId(getDefaultSubscription());
1253
1254 }
1255
1256 public int getCdmaEriIconIndexUsingSubId(long subId) {
1257 return getPhone(subId).getCdmaEriIconIndex();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001258 }
1259
1260 /**
1261 * Returns the CDMA ERI icon mode,
1262 * 0 - ON
1263 * 1 - FLASHING
1264 */
1265 public int getCdmaEriIconMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001266 return getCdmaEriIconModeUsingSubId(getDefaultSubscription());
1267 }
1268
1269 public int getCdmaEriIconModeUsingSubId(long subId) {
1270 return getPhone(subId).getCdmaEriIconMode();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001271 }
1272
1273 /**
1274 * Returns the CDMA ERI text,
1275 */
1276 public String getCdmaEriText() {
Wink Saville36469e72014-06-11 15:17:00 -07001277 return getCdmaEriTextUsingSubId(getDefaultSubscription());
1278 }
1279
1280 public String getCdmaEriTextUsingSubId(long subId) {
1281 return getPhone(subId).getCdmaEriText();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001282 }
1283
1284 /**
1285 * Returns true if CDMA provisioning needs to run.
1286 */
1287 public boolean needsOtaServiceProvisioning() {
1288 return mPhone.needsOtaServiceProvisioning();
1289 }
1290
1291 /**
1292 * Returns the unread count of voicemails
1293 */
1294 public int getVoiceMessageCount() {
Wink Saville36469e72014-06-11 15:17:00 -07001295 return getVoiceMessageCountUsingSubId(getDefaultSubscription());
1296 }
1297
1298 /**
1299 * Returns the unread count of voicemails for a subId
1300 */
1301 public int getVoiceMessageCountUsingSubId( long subId) {
1302 return getPhone(subId).getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001303 }
1304
1305 /**
1306 * Returns the data network type
1307 *
1308 * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1309 */
1310 @Override
1311 public int getNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001312 return getNetworkTypeUsingSubId(getDefaultSubscription());
1313 }
1314
1315 /**
1316 * Returns the network type for a subId
1317 */
1318 @Override
1319 public int getNetworkTypeUsingSubId(long subId) {
1320 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001321 }
1322
1323 /**
1324 * Returns the data network type
1325 */
1326 @Override
1327 public int getDataNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001328 return getDataNetworkTypeUsingSubId(getDefaultSubscription());
1329 }
1330
1331 /**
1332 * Returns the data network type for a subId
1333 */
1334 @Override
1335 public int getDataNetworkTypeUsingSubId(long subId) {
1336 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001337 }
1338
1339 /**
1340 * Returns the data network type
1341 */
1342 @Override
1343 public int getVoiceNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001344 return getVoiceNetworkTypeUsingSubId(getDefaultSubscription());
1345 }
1346
1347 /**
1348 * Returns the Voice network type for a subId
1349 */
1350 @Override
1351 public int getVoiceNetworkTypeUsingSubId(long subId) {
1352 return getPhone(subId).getServiceState().getVoiceNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001353 }
1354
1355 /**
1356 * @return true if a ICC card is present
1357 */
1358 public boolean hasIccCard() {
Wink Saville36469e72014-06-11 15:17:00 -07001359 // FIXME Make changes to pass defaultSimId of type int
1360 return hasIccCardUsingSlotId(getDefaultSubscription());
1361 }
1362
1363 /**
1364 * @return true if a ICC card is present for a slotId
1365 */
1366 public boolean hasIccCardUsingSlotId(long slotId) {
1367 return getPhone(slotId).getIccCard().hasIccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001368 }
1369
1370 /**
1371 * Return if the current radio is LTE on CDMA. This
1372 * is a tri-state return value as for a period of time
1373 * the mode may be unknown.
1374 *
1375 * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
Jake Hambye994d462014-02-03 13:10:13 -08001376 * or {@link Phone#LTE_ON_CDMA_TRUE}
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001377 */
1378 public int getLteOnCdmaMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001379 return getLteOnCdmaModeUsingSubId(getDefaultSubscription());
1380 }
1381
1382 public int getLteOnCdmaModeUsingSubId(long subId) {
1383 return getPhone(subId).getLteOnCdmaMode();
1384 }
1385
1386 public void setPhone(Phone phone) {
1387 mPhone = phone;
1388 }
1389
1390 /**
1391 * {@hide}
1392 * Returns Default subId, 0 in the case of single standby.
1393 */
1394 private long getDefaultSubscription() {
1395 return SubscriptionManager.getDefaultSubId();
1396 }
1397
1398 private long getPreferredVoiceSubscription() {
1399 return SubscriptionManager.getDefaultVoiceSubId();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001400 }
Ihab Awadf2177b72013-11-25 13:33:23 -08001401
1402 /**
1403 * @see android.telephony.TelephonyManager.WifiCallingChoices
1404 */
1405 public int getWhenToMakeWifiCalls() {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001406 return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1407 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
Ihab Awadf2177b72013-11-25 13:33:23 -08001408 }
1409
1410 /**
1411 * @see android.telephony.TelephonyManager.WifiCallingChoices
1412 */
1413 public void setWhenToMakeWifiCalls(int preference) {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001414 if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1415 Settings.System.putInt(mPhone.getContext().getContentResolver(),
1416 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
Ihab Awadf9e92732013-12-05 18:02:52 -08001417 }
1418
Sailesh Nepald1e68152013-12-12 19:08:02 -08001419 private static int getWhenToMakeWifiCallsDefaultPreference() {
1420 // TODO(sail): Use a build property to choose this value.
Evan Charlton9829e882013-12-19 15:30:38 -08001421 return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
Ihab Awadf2177b72013-11-25 13:33:23 -08001422 }
Shishir Agrawal69f68122013-12-16 17:25:49 -08001423
Shishir Agrawal566b7612013-10-28 14:41:00 -07001424 @Override
1425 public int iccOpenLogicalChannel(String AID) {
Junda Liua2e36012014-07-09 18:30:01 -07001426 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001427
1428 if (DBG) log("iccOpenLogicalChannel: " + AID);
1429 Integer channel = (Integer)sendRequest(CMD_OPEN_CHANNEL, AID);
1430 if (DBG) log("iccOpenLogicalChannel: " + channel);
Jake Hambye994d462014-02-03 13:10:13 -08001431 return channel;
Shishir Agrawal566b7612013-10-28 14:41:00 -07001432 }
1433
1434 @Override
1435 public boolean iccCloseLogicalChannel(int channel) {
Junda Liua2e36012014-07-09 18:30:01 -07001436 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001437
1438 if (DBG) log("iccCloseLogicalChannel: " + channel);
1439 if (channel < 0) {
1440 return false;
1441 }
Jake Hambye994d462014-02-03 13:10:13 -08001442 Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
Shishir Agrawal566b7612013-10-28 14:41:00 -07001443 if (DBG) log("iccCloseLogicalChannel: " + success);
1444 return success;
1445 }
1446
1447 @Override
1448 public String iccTransmitApduLogicalChannel(int channel, int cla,
1449 int command, int p1, int p2, int p3, String data) {
Junda Liua2e36012014-07-09 18:30:01 -07001450 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001451
1452 if (DBG) {
1453 log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1454 " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1455 " data=" + data);
1456 }
1457
1458 if (channel < 0) {
1459 return "";
1460 }
1461
1462 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU,
1463 new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1464 if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1465
1466 // If the payload is null, there was an error. Indicate that by returning
1467 // an empty string.
1468 if (response.payload == null) {
1469 return "";
1470 }
1471
1472 // Append the returned status code to the end of the response payload.
1473 String s = Integer.toHexString(
1474 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1475 s = IccUtils.bytesToHexString(response.payload) + s;
1476 return s;
1477 }
Jake Hambye994d462014-02-03 13:10:13 -08001478
Evan Charltonc66da362014-05-16 14:06:40 -07001479 @Override
1480 public String sendEnvelopeWithStatus(String content) {
Junda Liua2e36012014-07-09 18:30:01 -07001481 enforceModifyPermissionOrCarrierPrivilege();
Evan Charltonc66da362014-05-16 14:06:40 -07001482
1483 IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
1484 if (response.payload == null) {
1485 return "";
1486 }
1487
1488 // Append the returned status code to the end of the response payload.
1489 String s = Integer.toHexString(
1490 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1491 s = IccUtils.bytesToHexString(response.payload) + s;
1492 return s;
1493 }
1494
Jake Hambye994d462014-02-03 13:10:13 -08001495 /**
1496 * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1497 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1498 *
1499 * @param itemID the ID of the item to read
1500 * @return the NV item as a String, or null on error.
1501 */
1502 @Override
1503 public String nvReadItem(int itemID) {
Junda Liua2e36012014-07-09 18:30:01 -07001504 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001505 if (DBG) log("nvReadItem: item " + itemID);
1506 String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
1507 if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
1508 return value;
1509 }
1510
1511 /**
1512 * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1513 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1514 *
1515 * @param itemID the ID of the item to read
1516 * @param itemValue the value to write, as a String
1517 * @return true on success; false on any failure
1518 */
1519 @Override
1520 public boolean nvWriteItem(int itemID, String itemValue) {
Junda Liua2e36012014-07-09 18:30:01 -07001521 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001522 if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
1523 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
1524 new Pair<Integer, String>(itemID, itemValue));
1525 if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
1526 return success;
1527 }
1528
1529 /**
1530 * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
1531 * Used for device configuration by some CDMA operators.
1532 *
1533 * @param preferredRoamingList byte array containing the new PRL
1534 * @return true on success; false on any failure
1535 */
1536 @Override
1537 public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
Junda Liua2e36012014-07-09 18:30:01 -07001538 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001539 if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
1540 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
1541 if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
1542 return success;
1543 }
1544
1545 /**
1546 * Perform the specified type of NV config reset.
1547 * Used for device configuration by some CDMA operators.
1548 *
1549 * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
1550 * @return true on success; false on any failure
1551 */
1552 @Override
1553 public boolean nvResetConfig(int resetType) {
Junda Liua2e36012014-07-09 18:30:01 -07001554 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001555 if (DBG) log("nvResetConfig: type " + resetType);
1556 Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
1557 if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
1558 return success;
1559 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001560
1561 /**
Wink Saville36469e72014-06-11 15:17:00 -07001562 * {@hide}
1563 * Returns Default sim, 0 in the case of single standby.
1564 */
1565 public int getDefaultSim() {
1566 //TODO Need to get it from Telephony Devcontroller
1567 return 0;
1568 }
1569
1570 public String[] getPcscfAddress() {
1571 enforceReadPermission();
1572 return mPhone.getPcscfAddress();
1573 }
1574
1575 public void setImsRegistrationState(boolean registered) {
1576 enforceModifyPermission();
1577 mPhone.setImsRegistrationState(registered);
1578 }
1579
1580 /**
Junda Liu84d15a22014-07-02 11:21:04 -07001581 * Get the calculated preferred network type.
1582 * Used for debugging incorrect network type.
1583 *
1584 * @return the preferred network type, defined in RILConstants.java.
1585 */
1586 @Override
1587 public int getCalculatedPreferredNetworkType() {
1588 enforceReadPermission();
1589 return PhoneFactory.calculatePreferredNetworkType(mPhone.getContext());
1590 }
1591
1592 /**
Jake Hamby7c27be32014-03-03 13:25:59 -08001593 * Get the preferred network type.
1594 * Used for device configuration by some CDMA operators.
1595 *
1596 * @return the preferred network type, defined in RILConstants.java.
1597 */
1598 @Override
1599 public int getPreferredNetworkType() {
Junda Liua2e36012014-07-09 18:30:01 -07001600 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001601 if (DBG) log("getPreferredNetworkType");
1602 int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null);
1603 int networkType = (result != null ? result[0] : -1);
1604 if (DBG) log("getPreferredNetworkType: " + networkType);
1605 return networkType;
1606 }
1607
1608 /**
1609 * Set the preferred network type.
1610 * Used for device configuration by some CDMA operators.
1611 *
1612 * @param networkType the preferred network type, defined in RILConstants.java.
1613 * @return true on success; false on any failure.
1614 */
1615 @Override
1616 public boolean setPreferredNetworkType(int networkType) {
Junda Liua2e36012014-07-09 18:30:01 -07001617 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001618 if (DBG) log("setPreferredNetworkType: type " + networkType);
1619 Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType);
1620 if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
Junda Liu80bc0d12014-07-14 16:36:44 -07001621 if (success) {
1622 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1623 Settings.Global.PREFERRED_NETWORK_MODE, networkType);
1624 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001625 return success;
1626 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001627
1628 /**
Junda Liu787bc7e2014-06-30 13:38:02 -07001629 * Set the CDMA subscription source.
1630 * Used for device supporting both NV and RUIM for CDMA.
1631 *
1632 * @param subscriptionType the subscription type, 0 for RUIM, 1 for NV.
1633 * @return true on success; false on any failure.
1634 */
1635 @Override
1636 public boolean setCdmaSubscription(int subscriptionType) {
Junda Liua2e36012014-07-09 18:30:01 -07001637 enforceModifyPermissionOrCarrierPrivilege();
Junda Liu787bc7e2014-06-30 13:38:02 -07001638 if (DBG) log("setCdmaSubscription: type " + subscriptionType);
1639 if (subscriptionType != mPhone.CDMA_SUBSCRIPTION_RUIM_SIM &&
1640 subscriptionType != mPhone.CDMA_SUBSCRIPTION_NV) {
1641 loge("setCdmaSubscription: unsupported subscriptionType.");
1642 return false;
1643 }
1644 Boolean success = (Boolean) sendRequest(CMD_SET_CDMA_SUBSCRIPTION, subscriptionType);
1645 if (DBG) log("setCdmaSubscription: " + (success ? "ok" : "fail"));
1646 if (success) {
1647 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1648 Settings.Global.CDMA_SUBSCRIPTION_MODE, subscriptionType);
1649 }
1650 return success;
1651 }
1652
1653 /**
Robert Greenwalted86e582014-05-21 20:03:20 -07001654 * Set mobile data enabled
1655 * Used by the user through settings etc to turn on/off mobile data
1656 *
1657 * @param enable {@code true} turn turn data on, else {@code false}
1658 */
1659 @Override
1660 public void setDataEnabled(boolean enable) {
1661 enforceModifyPermission();
1662 mPhone.setDataEnabled(enable);
1663 }
1664
1665 /**
Robert Greenwalt646120a2014-05-23 11:54:03 -07001666 * Get whether mobile data is enabled.
1667 *
1668 * Note that this used to be available from ConnectivityService, gated by
1669 * ACCESS_NETWORK_STATE permission, so this will accept either that or
1670 * our MODIFY_PHONE_STATE.
Robert Greenwalted86e582014-05-21 20:03:20 -07001671 *
1672 * @return {@code true} if data is enabled else {@code false}
1673 */
1674 @Override
1675 public boolean getDataEnabled() {
Robert Greenwalt646120a2014-05-23 11:54:03 -07001676 try {
1677 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
1678 null);
1679 } catch (Exception e) {
1680 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
1681 null);
1682 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001683 return mPhone.getDataEnabled();
1684 }
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001685
1686 @Override
1687 public int hasCarrierPrivileges() {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001688 return UiccController.getInstance().getUiccCard().getCarrierPrivilegeStatusForCurrentTransaction(
1689 mPhone.getContext().getPackageManager());
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001690 }
Junda Liu29340342014-07-10 15:23:27 -07001691
1692 @Override
Shishir Agrawal6d5a2852014-07-11 16:32:57 -07001693 public int checkCarrierPrivilegesForPackage(String pkgname) {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001694 return UiccController.getInstance().getUiccCard().getCarrierPrivilegeStatus(
1695 mPhone.getContext().getPackageManager(), pkgname);
Junda Liu29340342014-07-10 15:23:27 -07001696 }
Derek Tan89e89d42014-07-08 17:00:10 -07001697
1698 @Override
1699 public void enableSimplifiedNetworkSettings(long subId, boolean enable) {
Derek Tan352d8cd2014-07-12 12:57:11 -07001700 enforceModifyPermissionOrCarrierPrivilege();
Derek Tan89e89d42014-07-08 17:00:10 -07001701 if (enable) {
1702 mSimplifiedNetworkSettings.add(subId);
1703 } else {
1704 mSimplifiedNetworkSettings.remove(subId);
1705 }
1706 }
1707
1708 @Override
1709 public boolean getSimplifiedNetworkSettingsEnabled(long subId) {
1710 enforceReadPermission();
1711 return mSimplifiedNetworkSettings.contains(subId);
1712 }
Derek Tan7226c842014-07-02 17:42:23 -07001713
1714 @Override
1715 public void setLine1NumberForDisplay(long subId, String alphaTag, String number) {
Derek Tan352d8cd2014-07-12 12:57:11 -07001716 enforceModifyPermissionOrCarrierPrivilege();
Derek Tan7226c842014-07-02 17:42:23 -07001717 mAdnRecordsForDisplay.put(subId, new AdnRecord(alphaTag, number));
1718 }
1719
1720 @Override
1721 public String getLine1NumberForDisplay(long subId) {
1722 enforceReadPermission();
1723 if (!mAdnRecordsForDisplay.containsKey(subId)) {
1724 return null;
1725 }
1726 AdnRecord adnRecord = mAdnRecordsForDisplay.get(subId);
1727 if (adnRecord.getNumber() == null || adnRecord.getNumber().isEmpty()) {
1728 return null;
1729 }
1730 return adnRecord.getNumber();
1731 }
1732
1733 @Override
1734 public String getLine1AlphaTagForDisplay(long subId) {
1735 enforceReadPermission();
1736 if (!mAdnRecordsForDisplay.containsKey(subId)) {
1737 return null;
1738 }
1739 AdnRecord adnRecord = mAdnRecordsForDisplay.get(subId);
1740 if (adnRecord.getAlphaTag() == null || adnRecord.getAlphaTag().isEmpty()) {
1741 return null;
1742 }
1743 return adnRecord.getAlphaTag();
1744 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001745}