blob: 59cd3d6d6d59703249d714b769cf1c47c81ee37c [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 Agrawaleb8771e2014-07-22 11:24:08 -070065import com.android.internal.telephony.uicc.UiccCard;
Shishir Agrawal60f9c952014-06-23 12:00:43 -070066import com.android.internal.telephony.uicc.UiccCarrierPrivilegeRules;
Shishir Agrawal566b7612013-10-28 14:41:00 -070067import com.android.internal.telephony.uicc.UiccController;
Jake Hambye994d462014-02-03 13:10:13 -080068import com.android.internal.util.HexDump;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070069
Wink Saville36469e72014-06-11 15:17:00 -070070import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
71
Santos Cordon7d4ddf62013-07-10 11:58:08 -070072import java.util.ArrayList;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070073import java.util.HashMap;
Derek Tan89e89d42014-07-08 17:00:10 -070074import java.util.HashSet;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070075import java.util.Iterator;
Jake Hambye994d462014-02-03 13:10:13 -080076import java.util.List;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070077import java.util.Map;
Derek Tan89e89d42014-07-08 17:00:10 -070078import java.util.Set;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070079
80/**
81 * Implementation of the ITelephony interface.
82 */
Santos Cordon117fee72014-05-16 17:56:12 -070083public class PhoneInterfaceManager extends ITelephony.Stub {
Santos Cordon7d4ddf62013-07-10 11:58:08 -070084 private static final String LOG_TAG = "PhoneInterfaceManager";
85 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
86 private static final boolean DBG_LOC = false;
87
88 // Message codes used with mMainThreadHandler
89 private static final int CMD_HANDLE_PIN_MMI = 1;
90 private static final int CMD_HANDLE_NEIGHBORING_CELL = 2;
91 private static final int EVENT_NEIGHBORING_CELL_DONE = 3;
92 private static final int CMD_ANSWER_RINGING_CALL = 4;
93 private static final int CMD_END_CALL = 5; // not used yet
94 private static final int CMD_SILENCE_RINGER = 6;
Shishir Agrawal566b7612013-10-28 14:41:00 -070095 private static final int CMD_TRANSMIT_APDU = 7;
96 private static final int EVENT_TRANSMIT_APDU_DONE = 8;
97 private static final int CMD_OPEN_CHANNEL = 9;
98 private static final int EVENT_OPEN_CHANNEL_DONE = 10;
99 private static final int CMD_CLOSE_CHANNEL = 11;
100 private static final int EVENT_CLOSE_CHANNEL_DONE = 12;
Jake Hambye994d462014-02-03 13:10:13 -0800101 private static final int CMD_NV_READ_ITEM = 13;
102 private static final int EVENT_NV_READ_ITEM_DONE = 14;
103 private static final int CMD_NV_WRITE_ITEM = 15;
104 private static final int EVENT_NV_WRITE_ITEM_DONE = 16;
105 private static final int CMD_NV_WRITE_CDMA_PRL = 17;
106 private static final int EVENT_NV_WRITE_CDMA_PRL_DONE = 18;
107 private static final int CMD_NV_RESET_CONFIG = 19;
108 private static final int EVENT_NV_RESET_CONFIG_DONE = 20;
Jake Hamby7c27be32014-03-03 13:25:59 -0800109 private static final int CMD_GET_PREFERRED_NETWORK_TYPE = 21;
110 private static final int EVENT_GET_PREFERRED_NETWORK_TYPE_DONE = 22;
111 private static final int CMD_SET_PREFERRED_NETWORK_TYPE = 23;
112 private static final int EVENT_SET_PREFERRED_NETWORK_TYPE_DONE = 24;
Sailesh Nepal35b59452014-03-06 09:26:56 -0800113 private static final int CMD_SEND_ENVELOPE = 25;
114 private static final int EVENT_SEND_ENVELOPE_DONE = 26;
Junda Liu787bc7e2014-06-30 13:38:02 -0700115 private static final int CMD_SET_CDMA_SUBSCRIPTION = 27;
116 private static final int EVENT_SET_CDMA_SUBSCRIPTION_DONE = 28;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700117
118 /** The singleton instance. */
119 private static PhoneInterfaceManager sInstance;
120
121 PhoneGlobals mApp;
122 Phone mPhone;
123 CallManager mCM;
124 AppOpsManager mAppOps;
125 MainThreadHandler mMainThreadHandler;
126
127 /**
Derek Tan89e89d42014-07-08 17:00:10 -0700128 * Indicates if Android should display a simplified Mobile Network Settings UI in a specific
129 * subscription.
130 */
131 Set<Long> mSimplifiedNetworkSettings;
Derek Tan7226c842014-07-02 17:42:23 -0700132 Map<Long, AdnRecord> mAdnRecordsForDisplay;
Derek Tan89e89d42014-07-08 17:00:10 -0700133
134 /**
Shishir Agrawal566b7612013-10-28 14:41:00 -0700135 * A request object to use for transmitting data to an ICC.
136 */
137 private static final class IccAPDUArgument {
138 public int channel, cla, command, p1, p2, p3;
139 public String data;
140
141 public IccAPDUArgument(int channel, int cla, int command,
142 int p1, int p2, int p3, String data) {
143 this.channel = channel;
144 this.cla = cla;
145 this.command = command;
146 this.p1 = p1;
147 this.p2 = p2;
148 this.p3 = p3;
149 this.data = data;
150 }
151 }
152
153 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700154 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
155 * request after sending. The main thread will notify the request when it is complete.
156 */
157 private static final class MainThreadRequest {
158 /** The argument to use for the request */
159 public Object argument;
160 /** The result of the request that is run on the main thread */
161 public Object result;
162
163 public MainThreadRequest(Object argument) {
164 this.argument = argument;
165 }
166 }
167
Sailesh Nepalcc0375f2013-11-13 09:15:18 -0800168 private static final class IncomingThirdPartyCallArgs {
169 public final ComponentName component;
170 public final String callId;
171 public final String callerDisplayName;
172
173 public IncomingThirdPartyCallArgs(ComponentName component, String callId,
174 String callerDisplayName) {
175 this.component = component;
176 this.callId = callId;
177 this.callerDisplayName = callerDisplayName;
178 }
179 }
180
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700181 /**
182 * A handler that processes messages on the main thread in the phone process. Since many
183 * of the Phone calls are not thread safe this is needed to shuttle the requests from the
184 * inbound binder threads to the main thread in the phone process. The Binder thread
185 * may provide a {@link MainThreadRequest} object in the msg.obj field that they are waiting
186 * on, which will be notified when the operation completes and will contain the result of the
187 * request.
188 *
189 * <p>If a MainThreadRequest object is provided in the msg.obj field,
190 * note that request.result must be set to something non-null for the calling thread to
191 * unblock.
192 */
193 private final class MainThreadHandler extends Handler {
194 @Override
195 public void handleMessage(Message msg) {
196 MainThreadRequest request;
197 Message onCompleted;
198 AsyncResult ar;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700199 UiccCard uiccCard = UiccController.getInstance().getUiccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700200
201 switch (msg.what) {
202 case CMD_HANDLE_PIN_MMI:
203 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800204 request.result = mPhone.handlePinMmi((String) request.argument);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700205 // Wake up the requesting thread
206 synchronized (request) {
207 request.notifyAll();
208 }
209 break;
210
211 case CMD_HANDLE_NEIGHBORING_CELL:
212 request = (MainThreadRequest) msg.obj;
213 onCompleted = obtainMessage(EVENT_NEIGHBORING_CELL_DONE,
214 request);
215 mPhone.getNeighboringCids(onCompleted);
216 break;
217
218 case EVENT_NEIGHBORING_CELL_DONE:
219 ar = (AsyncResult) msg.obj;
220 request = (MainThreadRequest) ar.userObj;
221 if (ar.exception == null && ar.result != null) {
222 request.result = ar.result;
223 } else {
224 // create an empty list to notify the waiting thread
Jake Hambye994d462014-02-03 13:10:13 -0800225 request.result = new ArrayList<NeighboringCellInfo>(0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700226 }
227 // Wake up the requesting thread
228 synchronized (request) {
229 request.notifyAll();
230 }
231 break;
232
233 case CMD_ANSWER_RINGING_CALL:
234 answerRingingCallInternal();
235 break;
236
237 case CMD_SILENCE_RINGER:
238 silenceRingerInternal();
239 break;
240
241 case CMD_END_CALL:
242 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800243 boolean hungUp;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700244 int phoneType = mPhone.getPhoneType();
245 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
246 // CDMA: If the user presses the Power button we treat it as
247 // ending the complete call session
248 hungUp = PhoneUtils.hangupRingingAndActive(mPhone);
249 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
250 // GSM: End the call as per the Phone state
251 hungUp = PhoneUtils.hangup(mCM);
252 } else {
253 throw new IllegalStateException("Unexpected phone type: " + phoneType);
254 }
255 if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up"));
256 request.result = hungUp;
257 // Wake up the requesting thread
258 synchronized (request) {
259 request.notifyAll();
260 }
261 break;
262
Shishir Agrawal566b7612013-10-28 14:41:00 -0700263 case CMD_TRANSMIT_APDU:
264 request = (MainThreadRequest) msg.obj;
265 IccAPDUArgument argument = (IccAPDUArgument) request.argument;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700266 if (uiccCard == null) {
267 loge("iccTransmitApduLogicalChannel: No UICC");
268 request.result = new IccIoResult(0x6F, 0, (byte[])null);
269 synchronized (request) {
270 request.notifyAll();
271 }
272 } else {
273 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_DONE, request);
274 uiccCard.iccTransmitApduLogicalChannel(
Shishir Agrawal566b7612013-10-28 14:41:00 -0700275 argument.channel, argument.cla, argument.command,
276 argument.p1, argument.p2, argument.p3, argument.data,
277 onCompleted);
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700278 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700279 break;
280
281 case EVENT_TRANSMIT_APDU_DONE:
282 ar = (AsyncResult) msg.obj;
283 request = (MainThreadRequest) ar.userObj;
284 if (ar.exception == null && ar.result != null) {
285 request.result = ar.result;
286 } else {
287 request.result = new IccIoResult(0x6F, 0, (byte[])null);
288 if (ar.result == null) {
289 loge("iccTransmitApduLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800290 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700291 loge("iccTransmitApduLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800292 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700293 } else {
294 loge("iccTransmitApduLogicalChannel: Unknown exception");
295 }
296 }
297 synchronized (request) {
298 request.notifyAll();
299 }
300 break;
301
Derek Tan4d5e5c12014-02-04 11:54:58 -0800302 case CMD_SEND_ENVELOPE:
303 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700304 if (uiccCard == null) {
305 loge("sendEnvelopeWithStatus: No UICC");
306 request.result = new IccIoResult(0x6F, 0, (byte[])null);
307 synchronized (request) {
308 request.notifyAll();
309 }
310 } else {
311 onCompleted = obtainMessage(EVENT_SEND_ENVELOPE_DONE, request);
312 uiccCard.sendEnvelopeWithStatus((String)request.argument, onCompleted);
313 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800314 break;
315
316 case EVENT_SEND_ENVELOPE_DONE:
317 ar = (AsyncResult) msg.obj;
318 request = (MainThreadRequest) ar.userObj;
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700319 if (ar.exception == null && ar.result != null) {
320 request.result = ar.result;
Derek Tan4d5e5c12014-02-04 11:54:58 -0800321 } else {
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700322 request.result = new IccIoResult(0x6F, 0, (byte[])null);
323 if (ar.result == null) {
324 loge("sendEnvelopeWithStatus: Empty response");
325 } else if (ar.exception instanceof CommandException) {
326 loge("sendEnvelopeWithStatus: CommandException: " +
327 ar.exception);
328 } else {
329 loge("sendEnvelopeWithStatus: exception:" + ar.exception);
330 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800331 }
332 synchronized (request) {
333 request.notifyAll();
334 }
335 break;
336
Shishir Agrawal566b7612013-10-28 14:41:00 -0700337 case CMD_OPEN_CHANNEL:
338 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700339 if (uiccCard == null) {
340 loge("iccOpenLogicalChannel: No UICC");
341 request.result = new IccIoResult(0x6F, 0, (byte[])null);
342 synchronized (request) {
343 request.notifyAll();
344 }
345 } else {
346 onCompleted = obtainMessage(EVENT_OPEN_CHANNEL_DONE, request);
347 uiccCard.iccOpenLogicalChannel((String)request.argument, onCompleted);
348 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700349 break;
350
351 case EVENT_OPEN_CHANNEL_DONE:
352 ar = (AsyncResult) msg.obj;
353 request = (MainThreadRequest) ar.userObj;
354 if (ar.exception == null && ar.result != null) {
Jake Hambye994d462014-02-03 13:10:13 -0800355 request.result = ((int[]) ar.result)[0];
Shishir Agrawal566b7612013-10-28 14:41:00 -0700356 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800357 request.result = -1;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700358 if (ar.result == null) {
359 loge("iccOpenLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800360 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700361 loge("iccOpenLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800362 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700363 } else {
364 loge("iccOpenLogicalChannel: Unknown exception");
365 }
366 }
367 synchronized (request) {
368 request.notifyAll();
369 }
370 break;
371
372 case CMD_CLOSE_CHANNEL:
373 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700374 if (uiccCard == null) {
375 loge("iccCloseLogicalChannel: No UICC");
376 request.result = new IccIoResult(0x6F, 0, (byte[])null);
377 synchronized (request) {
378 request.notifyAll();
379 }
380 } else {
381 onCompleted = obtainMessage(EVENT_CLOSE_CHANNEL_DONE, request);
382 uiccCard.iccCloseLogicalChannel((Integer) request.argument, onCompleted);
383 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700384 break;
385
386 case EVENT_CLOSE_CHANNEL_DONE:
Jake Hambye994d462014-02-03 13:10:13 -0800387 handleNullReturnEvent(msg, "iccCloseLogicalChannel");
388 break;
389
390 case CMD_NV_READ_ITEM:
391 request = (MainThreadRequest) msg.obj;
392 onCompleted = obtainMessage(EVENT_NV_READ_ITEM_DONE, request);
393 mPhone.nvReadItem((Integer) request.argument, onCompleted);
394 break;
395
396 case EVENT_NV_READ_ITEM_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700397 ar = (AsyncResult) msg.obj;
398 request = (MainThreadRequest) ar.userObj;
Jake Hambye994d462014-02-03 13:10:13 -0800399 if (ar.exception == null && ar.result != null) {
400 request.result = ar.result; // String
Shishir Agrawal566b7612013-10-28 14:41:00 -0700401 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800402 request.result = "";
403 if (ar.result == null) {
404 loge("nvReadItem: Empty response");
405 } else if (ar.exception instanceof CommandException) {
406 loge("nvReadItem: CommandException: " +
407 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700408 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800409 loge("nvReadItem: Unknown exception");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700410 }
411 }
412 synchronized (request) {
413 request.notifyAll();
414 }
415 break;
416
Jake Hambye994d462014-02-03 13:10:13 -0800417 case CMD_NV_WRITE_ITEM:
418 request = (MainThreadRequest) msg.obj;
419 onCompleted = obtainMessage(EVENT_NV_WRITE_ITEM_DONE, request);
420 Pair<Integer, String> idValue = (Pair<Integer, String>) request.argument;
421 mPhone.nvWriteItem(idValue.first, idValue.second, onCompleted);
422 break;
423
424 case EVENT_NV_WRITE_ITEM_DONE:
425 handleNullReturnEvent(msg, "nvWriteItem");
426 break;
427
428 case CMD_NV_WRITE_CDMA_PRL:
429 request = (MainThreadRequest) msg.obj;
430 onCompleted = obtainMessage(EVENT_NV_WRITE_CDMA_PRL_DONE, request);
431 mPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
432 break;
433
434 case EVENT_NV_WRITE_CDMA_PRL_DONE:
435 handleNullReturnEvent(msg, "nvWriteCdmaPrl");
436 break;
437
438 case CMD_NV_RESET_CONFIG:
439 request = (MainThreadRequest) msg.obj;
440 onCompleted = obtainMessage(EVENT_NV_RESET_CONFIG_DONE, request);
441 mPhone.nvResetConfig((Integer) request.argument, onCompleted);
442 break;
443
444 case EVENT_NV_RESET_CONFIG_DONE:
445 handleNullReturnEvent(msg, "nvResetConfig");
446 break;
447
Jake Hamby7c27be32014-03-03 13:25:59 -0800448 case CMD_GET_PREFERRED_NETWORK_TYPE:
449 request = (MainThreadRequest) msg.obj;
450 onCompleted = obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE_DONE, request);
451 mPhone.getPreferredNetworkType(onCompleted);
452 break;
453
454 case EVENT_GET_PREFERRED_NETWORK_TYPE_DONE:
455 ar = (AsyncResult) msg.obj;
456 request = (MainThreadRequest) ar.userObj;
457 if (ar.exception == null && ar.result != null) {
458 request.result = ar.result; // Integer
459 } else {
460 request.result = -1;
461 if (ar.result == null) {
462 loge("getPreferredNetworkType: Empty response");
463 } else if (ar.exception instanceof CommandException) {
464 loge("getPreferredNetworkType: CommandException: " +
465 ar.exception);
466 } else {
467 loge("getPreferredNetworkType: Unknown exception");
468 }
469 }
470 synchronized (request) {
471 request.notifyAll();
472 }
473 break;
474
475 case CMD_SET_PREFERRED_NETWORK_TYPE:
476 request = (MainThreadRequest) msg.obj;
477 onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);
478 int networkType = (Integer) request.argument;
479 mPhone.setPreferredNetworkType(networkType, onCompleted);
480 break;
481
482 case EVENT_SET_PREFERRED_NETWORK_TYPE_DONE:
483 handleNullReturnEvent(msg, "setPreferredNetworkType");
484 break;
485
Junda Liu787bc7e2014-06-30 13:38:02 -0700486 case CMD_SET_CDMA_SUBSCRIPTION:
487 request = (MainThreadRequest) msg.obj;
488 onCompleted = obtainMessage(EVENT_SET_CDMA_SUBSCRIPTION_DONE, request);
489 int subscriptionType = (Integer) request.argument;
490 mPhone.setCdmaSubscription(subscriptionType, onCompleted);
491 break;
492
493 case EVENT_SET_CDMA_SUBSCRIPTION_DONE:
494 handleNullReturnEvent(msg, "setCdmaSubscription");
495 break;
496
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700497 default:
498 Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
499 break;
500 }
501 }
Jake Hambye994d462014-02-03 13:10:13 -0800502
503 private void handleNullReturnEvent(Message msg, String command) {
504 AsyncResult ar = (AsyncResult) msg.obj;
505 MainThreadRequest request = (MainThreadRequest) ar.userObj;
506 if (ar.exception == null) {
507 request.result = true;
508 } else {
509 request.result = false;
510 if (ar.exception instanceof CommandException) {
511 loge(command + ": CommandException: " + ar.exception);
512 } else {
513 loge(command + ": Unknown exception");
514 }
515 }
516 synchronized (request) {
517 request.notifyAll();
518 }
519 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700520 }
521
522 /**
523 * Posts the specified command to be executed on the main thread,
524 * waits for the request to complete, and returns the result.
525 * @see #sendRequestAsync
526 */
527 private Object sendRequest(int command, Object argument) {
Santos Cordon500b0e02014-06-17 10:33:33 -0700528 return sendRequest(command, argument, null);
Wink Saville36469e72014-06-11 15:17:00 -0700529 }
530
531 /**
532 * Posts the specified command to be executed on the main thread,
533 * waits for the request to complete, and returns the result.
534 * @see #sendRequestAsync
535 */
536 private Object sendRequest(int command, Object argument, Object argument2) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700537 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
538 throw new RuntimeException("This method will deadlock if called from the main thread.");
539 }
540
541 MainThreadRequest request = new MainThreadRequest(argument);
542 Message msg = mMainThreadHandler.obtainMessage(command, request);
543 msg.sendToTarget();
544
545 // Wait for the request to complete
546 synchronized (request) {
547 while (request.result == null) {
548 try {
549 request.wait();
550 } catch (InterruptedException e) {
551 // Do nothing, go back and wait until the request is complete
552 }
553 }
554 }
555 return request.result;
556 }
557
558 /**
559 * Asynchronous ("fire and forget") version of sendRequest():
560 * Posts the specified command to be executed on the main thread, and
561 * returns immediately.
562 * @see #sendRequest
563 */
564 private void sendRequestAsync(int command) {
565 mMainThreadHandler.sendEmptyMessage(command);
566 }
567
568 /**
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -0700569 * Same as {@link #sendRequestAsync(int)} except it takes an argument.
570 * @see {@link #sendRequest(int,Object)}
571 */
572 private void sendRequestAsync(int command, Object argument) {
573 MainThreadRequest request = new MainThreadRequest(argument);
574 Message msg = mMainThreadHandler.obtainMessage(command, request);
575 msg.sendToTarget();
576 }
577
578 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700579 * Initialize the singleton PhoneInterfaceManager instance.
580 * This is only done once, at startup, from PhoneApp.onCreate().
581 */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700582 /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700583 synchronized (PhoneInterfaceManager.class) {
584 if (sInstance == null) {
Sailesh Nepal194161e2014-07-03 08:57:44 -0700585 sInstance = new PhoneInterfaceManager(app, phone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700586 } else {
587 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
588 }
589 return sInstance;
590 }
591 }
592
593 /** Private constructor; @see init() */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700594 private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700595 mApp = app;
596 mPhone = phone;
597 mCM = PhoneGlobals.getInstance().mCM;
Derek Tan89e89d42014-07-08 17:00:10 -0700598 mSimplifiedNetworkSettings = new HashSet<Long>();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700599 mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
600 mMainThreadHandler = new MainThreadHandler();
Derek Tan7226c842014-07-02 17:42:23 -0700601 mAdnRecordsForDisplay = new HashMap<Long, AdnRecord>();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700602 publish();
603 }
604
605 private void publish() {
606 if (DBG) log("publish: " + this);
607
608 ServiceManager.addService("phone", this);
609 }
610
Wink Saville36469e72014-06-11 15:17:00 -0700611 // returns phone associated with the subId.
612 // getPhone(0) returns default phone in single SIM mode.
613 private Phone getPhone(long subId) {
614 // FIXME: hack for the moment
615 return mPhone;
616 // return PhoneUtils.getPhoneUsingSubId(subId);
617 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700618 //
619 // Implementation of the ITelephony interface.
620 //
621
622 public void dial(String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700623 dialUsingSubId(getPreferredVoiceSubscription(), number);
624 }
625
626 public void dialUsingSubId(long subId, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700627 if (DBG) log("dial: " + number);
628 // No permission check needed here: This is just a wrapper around the
629 // ACTION_DIAL intent, which is available to any app since it puts up
630 // the UI before it does anything.
631
632 String url = createTelUrl(number);
633 if (url == null) {
634 return;
635 }
636
637 // PENDING: should we just silently fail if phone is offhook or ringing?
Wink Saville36469e72014-06-11 15:17:00 -0700638 PhoneConstants.State state = mCM.getState(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700639 if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
640 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
641 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Wink Saville36469e72014-06-11 15:17:00 -0700642 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700643 mApp.startActivity(intent);
644 }
645 }
646
647 public void call(String callingPackage, String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700648 callUsingSubId(getPreferredVoiceSubscription(), callingPackage, number);
649 }
650
651 public void callUsingSubId(long subId, String callingPackage, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700652 if (DBG) log("call: " + number);
653
654 // This is just a wrapper around the ACTION_CALL intent, but we still
655 // need to do a permission check since we're calling startActivity()
656 // from the context of the phone app.
657 enforceCallPermission();
658
659 if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
660 != AppOpsManager.MODE_ALLOWED) {
661 return;
662 }
663
664 String url = createTelUrl(number);
665 if (url == null) {
666 return;
667 }
668
669 Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
Wink Saville36469e72014-06-11 15:17:00 -0700670 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700671 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
672 mApp.startActivity(intent);
673 }
674
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700675 /**
676 * End a call based on call state
677 * @return true is a call was ended
678 */
679 public boolean endCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700680 return endCallUsingSubId(getDefaultSubscription());
681 }
682
683 /**
684 * End a call based on the call state of the subId
685 * @return true is a call was ended
686 */
687 public boolean endCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700688 enforceCallPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700689 return (Boolean) sendRequest(CMD_END_CALL, subId, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700690 }
691
692 public void answerRingingCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700693 answerRingingCallUsingSubId(getDefaultSubscription());
694 }
695
696 public void answerRingingCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700697 if (DBG) log("answerRingingCall...");
698 // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
699 // but that can probably wait till the big TelephonyManager API overhaul.
700 // For now, protect this call with the MODIFY_PHONE_STATE permission.
701 enforceModifyPermission();
702 sendRequestAsync(CMD_ANSWER_RINGING_CALL);
703 }
704
705 /**
706 * Make the actual telephony calls to implement answerRingingCall().
707 * This should only be called from the main thread of the Phone app.
708 * @see #answerRingingCall
709 *
710 * TODO: it would be nice to return true if we answered the call, or
711 * false if there wasn't actually a ringing incoming call, or some
712 * other error occurred. (In other words, pass back the return value
713 * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
714 * But that would require calling this method via sendRequest() rather
715 * than sendRequestAsync(), and right now we don't actually *need* that
716 * return value, so let's just return void for now.
717 */
718 private void answerRingingCallInternal() {
719 final boolean hasRingingCall = !mPhone.getRingingCall().isIdle();
720 if (hasRingingCall) {
721 final boolean hasActiveCall = !mPhone.getForegroundCall().isIdle();
722 final boolean hasHoldingCall = !mPhone.getBackgroundCall().isIdle();
723 if (hasActiveCall && hasHoldingCall) {
724 // Both lines are in use!
725 // TODO: provide a flag to let the caller specify what
726 // policy to use if both lines are in use. (The current
727 // behavior is hardwired to "answer incoming, end ongoing",
728 // which is how the CALL button is specced to behave.)
729 PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
730 return;
731 } else {
732 // answerCall() will automatically hold the current active
733 // call, if there is one.
734 PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
735 return;
736 }
737 } else {
738 // No call was ringing.
739 return;
740 }
741 }
742
743 public void silenceRinger() {
744 if (DBG) log("silenceRinger...");
745 // TODO: find a more appropriate permission to check here.
746 // (That can probably wait till the big TelephonyManager API overhaul.
747 // For now, protect this call with the MODIFY_PHONE_STATE permission.)
748 enforceModifyPermission();
749 sendRequestAsync(CMD_SILENCE_RINGER);
750 }
751
752 /**
753 * Internal implemenation of silenceRinger().
754 * This should only be called from the main thread of the Phone app.
755 * @see #silenceRinger
756 */
757 private void silenceRingerInternal() {
758 if ((mCM.getState() == PhoneConstants.State.RINGING)
759 && mApp.notifier.isRinging()) {
760 // Ringer is actually playing, so silence it.
761 if (DBG) log("silenceRingerInternal: silencing...");
762 mApp.notifier.silenceRinger();
763 }
764 }
765
766 public boolean isOffhook() {
Wink Saville36469e72014-06-11 15:17:00 -0700767 return isOffhookUsingSubId(getDefaultSubscription());
768 }
769
770 public boolean isOffhookUsingSubId(long subId) {
771 return (getPhone(subId).getState() == PhoneConstants.State.OFFHOOK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700772 }
773
774 public boolean isRinging() {
Wink Saville36469e72014-06-11 15:17:00 -0700775 return (isRingingUsingSubId(getDefaultSubscription()));
776 }
777
778 public boolean isRingingUsingSubId(long subId) {
779 return (getPhone(subId).getState() == PhoneConstants.State.RINGING);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700780 }
781
782 public boolean isIdle() {
Wink Saville36469e72014-06-11 15:17:00 -0700783 return isIdleUsingSubId(getDefaultSubscription());
784 }
785
786 public boolean isIdleUsingSubId(long subId) {
787 return (getPhone(subId).getState() == PhoneConstants.State.IDLE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700788 }
789
790 public boolean isSimPinEnabled() {
791 enforceReadPermission();
792 return (PhoneGlobals.getInstance().isSimPinEnabled());
793 }
794
795 public boolean supplyPin(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700796 return supplyPinUsingSubId(getDefaultSubscription(), pin);
797 }
798
799 public boolean supplyPinUsingSubId(long subId, String pin) {
800 int [] resultArray = supplyPinReportResultUsingSubId(subId, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700801 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
802 }
803
804 public boolean supplyPuk(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700805 return supplyPukUsingSubId(getDefaultSubscription(), puk, pin);
806 }
807
808 public boolean supplyPukUsingSubId(long subId, String puk, String pin) {
809 int [] resultArray = supplyPukReportResultUsingSubId(subId, puk, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700810 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
811 }
812
813 /** {@hide} */
814 public int[] supplyPinReportResult(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700815 return supplyPinReportResultUsingSubId(getDefaultSubscription(), pin);
816 }
817
818 public int[] supplyPinReportResultUsingSubId(long subId, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700819 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700820 final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700821 checkSimPin.start();
822 return checkSimPin.unlockSim(null, pin);
823 }
824
Wink Saville9de0f752013-10-22 19:04:03 -0700825 /** {@hide} */
826 public int[] supplyPukReportResult(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700827 return supplyPukReportResultUsingSubId(getDefaultSubscription(), puk, pin);
828 }
829
830 public int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700831 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700832 final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700833 checkSimPuk.start();
834 return checkSimPuk.unlockSim(puk, pin);
835 }
836
837 /**
Wink Saville9de0f752013-10-22 19:04:03 -0700838 * Helper thread to turn async call to SimCard#supplyPin into
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700839 * a synchronous one.
840 */
841 private static class UnlockSim extends Thread {
842
843 private final IccCard mSimCard;
844
845 private boolean mDone = false;
Wink Saville9de0f752013-10-22 19:04:03 -0700846 private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
847 private int mRetryCount = -1;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700848
849 // For replies from SimCard interface
850 private Handler mHandler;
851
852 // For async handler to identify request type
853 private static final int SUPPLY_PIN_COMPLETE = 100;
854
855 public UnlockSim(IccCard simCard) {
856 mSimCard = simCard;
857 }
858
859 @Override
860 public void run() {
861 Looper.prepare();
862 synchronized (UnlockSim.this) {
863 mHandler = new Handler() {
864 @Override
865 public void handleMessage(Message msg) {
866 AsyncResult ar = (AsyncResult) msg.obj;
867 switch (msg.what) {
868 case SUPPLY_PIN_COMPLETE:
869 Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
870 synchronized (UnlockSim.this) {
Wink Saville9de0f752013-10-22 19:04:03 -0700871 mRetryCount = msg.arg1;
872 if (ar.exception != null) {
873 if (ar.exception instanceof CommandException &&
874 ((CommandException)(ar.exception)).getCommandError()
875 == CommandException.Error.PASSWORD_INCORRECT) {
876 mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
877 } else {
878 mResult = PhoneConstants.PIN_GENERAL_FAILURE;
879 }
880 } else {
881 mResult = PhoneConstants.PIN_RESULT_SUCCESS;
882 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700883 mDone = true;
884 UnlockSim.this.notifyAll();
885 }
886 break;
887 }
888 }
889 };
890 UnlockSim.this.notifyAll();
891 }
892 Looper.loop();
893 }
894
895 /*
896 * Use PIN or PUK to unlock SIM card
897 *
898 * If PUK is null, unlock SIM card with PIN
899 *
900 * If PUK is not null, unlock SIM card with PUK and set PIN code
901 */
Wink Saville9de0f752013-10-22 19:04:03 -0700902 synchronized int[] unlockSim(String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700903
904 while (mHandler == null) {
905 try {
906 wait();
907 } catch (InterruptedException e) {
908 Thread.currentThread().interrupt();
909 }
910 }
911 Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
912
913 if (puk == null) {
914 mSimCard.supplyPin(pin, callback);
915 } else {
916 mSimCard.supplyPuk(puk, pin, callback);
917 }
918
919 while (!mDone) {
920 try {
921 Log.d(LOG_TAG, "wait for done");
922 wait();
923 } catch (InterruptedException e) {
924 // Restore the interrupted status
925 Thread.currentThread().interrupt();
926 }
927 }
928 Log.d(LOG_TAG, "done");
Wink Saville9de0f752013-10-22 19:04:03 -0700929 int[] resultArray = new int[2];
930 resultArray[0] = mResult;
931 resultArray[1] = mRetryCount;
932 return resultArray;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700933 }
934 }
935
936 public void updateServiceLocation() {
Wink Saville36469e72014-06-11 15:17:00 -0700937 updateServiceLocationUsingSubId(getDefaultSubscription());
938
939 }
940
941 public void updateServiceLocationUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700942 // No permission check needed here: this call is harmless, and it's
943 // needed for the ServiceState.requestStateUpdate() call (which is
944 // already intentionally exposed to 3rd parties.)
Wink Saville36469e72014-06-11 15:17:00 -0700945 getPhone(subId).updateServiceLocation();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700946 }
947
948 public boolean isRadioOn() {
Wink Saville36469e72014-06-11 15:17:00 -0700949 return isRadioOnUsingSubId(getDefaultSubscription());
950 }
951
952 public boolean isRadioOnUsingSubId(long subId) {
953 return getPhone(subId).getServiceState().getState() != ServiceState.STATE_POWER_OFF;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700954 }
955
956 public void toggleRadioOnOff() {
Wink Saville36469e72014-06-11 15:17:00 -0700957 toggleRadioOnOffUsingSubId(getDefaultSubscription());
958
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700959 }
Wink Saville36469e72014-06-11 15:17:00 -0700960
961 public void toggleRadioOnOffUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700962 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700963 getPhone(subId).setRadioPower(!isRadioOnUsingSubId(subId));
964 }
965
966 public boolean setRadio(boolean turnOn) {
967 return setRadioUsingSubId(getDefaultSubscription(), turnOn);
968 }
969
970 public boolean setRadioUsingSubId(long subId, boolean turnOn) {
971 enforceModifyPermission();
972 if ((getPhone(subId).getServiceState().getState() !=
973 ServiceState.STATE_POWER_OFF) != turnOn) {
974 toggleRadioOnOffUsingSubId(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700975 }
976 return true;
977 }
Wink Saville36469e72014-06-11 15:17:00 -0700978
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700979 public boolean setRadioPower(boolean turnOn) {
Wink Saville36469e72014-06-11 15:17:00 -0700980 return setRadioPowerUsingSubId(getDefaultSubscription(), turnOn);
981 }
982
983 public boolean setRadioPowerUsingSubId(long subId, boolean turnOn) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700984 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700985 getPhone(subId).setRadioPower(turnOn);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700986 return true;
987 }
988
Wink Saville36469e72014-06-11 15:17:00 -0700989 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700990 public boolean enableDataConnectivity() {
991 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700992 long subId = SubscriptionManager.getDefaultDataSubId();
993 getPhone(subId).setDataEnabled(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700994 return true;
995 }
996
Wink Saville36469e72014-06-11 15:17:00 -0700997 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700998 public boolean disableDataConnectivity() {
999 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001000 long subId = SubscriptionManager.getDefaultDataSubId();
1001 getPhone(subId).setDataEnabled(false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001002 return true;
1003 }
1004
Wink Saville36469e72014-06-11 15:17:00 -07001005 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001006 public boolean isDataConnectivityPossible() {
Wink Saville36469e72014-06-11 15:17:00 -07001007 long subId = SubscriptionManager.getDefaultDataSubId();
1008 return getPhone(subId).isDataConnectivityPossible();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001009 }
1010
1011 public boolean handlePinMmi(String dialString) {
Wink Saville36469e72014-06-11 15:17:00 -07001012 return handlePinMmiUsingSubId(getDefaultSubscription(), dialString);
1013 }
1014
1015 public boolean handlePinMmiUsingSubId(long subId, String dialString) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001016 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001017 return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001018 }
1019
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001020 public int getCallState() {
Wink Saville36469e72014-06-11 15:17:00 -07001021 return getCallStateUsingSubId(getDefaultSubscription());
1022 }
1023
1024 public int getCallStateUsingSubId(long subId) {
1025 return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001026 }
1027
1028 public int getDataState() {
Wink Saville36469e72014-06-11 15:17:00 -07001029 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1030 return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001031 }
1032
1033 public int getDataActivity() {
Wink Saville36469e72014-06-11 15:17:00 -07001034 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1035 return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001036 }
1037
1038 @Override
1039 public Bundle getCellLocation() {
1040 try {
1041 mApp.enforceCallingOrSelfPermission(
1042 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1043 } catch (SecurityException e) {
1044 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1045 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1046 // is the weaker precondition
1047 mApp.enforceCallingOrSelfPermission(
1048 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1049 }
1050
Jake Hambye994d462014-02-03 13:10:13 -08001051 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001052 if (DBG_LOC) log("getCellLocation: is active user");
1053 Bundle data = new Bundle();
1054 mPhone.getCellLocation().fillInNotifierBundle(data);
1055 return data;
1056 } else {
1057 if (DBG_LOC) log("getCellLocation: suppress non-active user");
1058 return null;
1059 }
1060 }
1061
1062 @Override
1063 public void enableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001064 enableLocationUpdatesUsingSubId(getDefaultSubscription());
1065 }
1066
1067 public void enableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001068 mApp.enforceCallingOrSelfPermission(
1069 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001070 getPhone(subId).enableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001071 }
1072
1073 @Override
1074 public void disableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001075 disableLocationUpdatesUsingSubId(getDefaultSubscription());
1076 }
1077
1078 public void disableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001079 mApp.enforceCallingOrSelfPermission(
1080 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001081 getPhone(subId).disableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001082 }
1083
1084 @Override
1085 @SuppressWarnings("unchecked")
1086 public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1087 try {
1088 mApp.enforceCallingOrSelfPermission(
1089 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1090 } catch (SecurityException e) {
1091 // If we have ACCESS_FINE_LOCATION permission, skip the check
1092 // for ACCESS_COARSE_LOCATION
1093 // A failure should throw the SecurityException from
1094 // ACCESS_COARSE_LOCATION since this is the weaker precondition
1095 mApp.enforceCallingOrSelfPermission(
1096 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1097 }
1098
1099 if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1100 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1101 return null;
1102 }
Jake Hambye994d462014-02-03 13:10:13 -08001103 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001104 if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1105
1106 ArrayList<NeighboringCellInfo> cells = null;
1107
1108 try {
1109 cells = (ArrayList<NeighboringCellInfo>) sendRequest(
Wink Saville36469e72014-06-11 15:17:00 -07001110 CMD_HANDLE_NEIGHBORING_CELL, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001111 } catch (RuntimeException e) {
Wink Saville36469e72014-06-11 15:17:00 -07001112 Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001113 }
1114 return cells;
1115 } else {
1116 if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1117 return null;
1118 }
1119 }
1120
1121
1122 @Override
1123 public List<CellInfo> getAllCellInfo() {
1124 try {
1125 mApp.enforceCallingOrSelfPermission(
1126 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1127 } catch (SecurityException e) {
1128 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1129 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1130 // is the weaker precondition
1131 mApp.enforceCallingOrSelfPermission(
1132 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1133 }
1134
Jake Hambye994d462014-02-03 13:10:13 -08001135 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001136 if (DBG_LOC) log("getAllCellInfo: is active user");
1137 return mPhone.getAllCellInfo();
1138 } else {
1139 if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1140 return null;
1141 }
1142 }
1143
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -07001144 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001145 public void setCellInfoListRate(int rateInMillis) {
1146 mPhone.setCellInfoListRate(rateInMillis);
1147 }
1148
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001149 //
1150 // Internal helper methods.
1151 //
1152
Jake Hambye994d462014-02-03 13:10:13 -08001153 private static boolean checkIfCallerIsSelfOrForegroundUser() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001154 boolean ok;
1155
1156 boolean self = Binder.getCallingUid() == Process.myUid();
1157 if (!self) {
1158 // Get the caller's user id then clear the calling identity
1159 // which will be restored in the finally clause.
1160 int callingUser = UserHandle.getCallingUserId();
1161 long ident = Binder.clearCallingIdentity();
1162
1163 try {
1164 // With calling identity cleared the current user is the foreground user.
1165 int foregroundUser = ActivityManager.getCurrentUser();
1166 ok = (foregroundUser == callingUser);
1167 if (DBG_LOC) {
1168 log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1169 + " callingUser=" + callingUser + " ok=" + ok);
1170 }
1171 } catch (Exception ex) {
1172 if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1173 ok = false;
1174 } finally {
1175 Binder.restoreCallingIdentity(ident);
1176 }
1177 } else {
1178 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1179 ok = true;
1180 }
1181 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1182 return ok;
1183 }
1184
1185 /**
1186 * Make sure the caller has the READ_PHONE_STATE permission.
1187 *
1188 * @throws SecurityException if the caller does not have the required permission
1189 */
1190 private void enforceReadPermission() {
1191 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
1192 }
1193
1194 /**
1195 * Make sure the caller has the MODIFY_PHONE_STATE permission.
1196 *
1197 * @throws SecurityException if the caller does not have the required permission
1198 */
1199 private void enforceModifyPermission() {
1200 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1201 }
1202
1203 /**
Junda Liua2e36012014-07-09 18:30:01 -07001204 * Make sure either system app or the caller has carrier privilege.
1205 *
1206 * @throws SecurityException if the caller does not have the required permission/privilege
1207 */
1208 private void enforceModifyPermissionOrCarrierPrivilege() {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001209 int permission = mApp.checkCallingOrSelfPermission(
1210 android.Manifest.permission.MODIFY_PHONE_STATE);
1211 if (permission == PackageManager.PERMISSION_GRANTED) {
1212 return;
1213 }
1214
1215 log("No modify permission, check carrier privilege next.");
1216 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1217 loge("No Carrier Privilege.");
1218 throw new SecurityException("No modify permission or carrier privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001219 }
1220 }
1221
1222 /**
1223 * Make sure the caller has carrier privilege.
1224 *
1225 * @throws SecurityException if the caller does not have the required permission
1226 */
1227 private void enforceCarrierPrivilege() {
1228 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001229 loge("No Carrier Privilege.");
1230 throw new SecurityException("No Carrier Privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001231 }
1232 }
1233
1234 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001235 * Make sure the caller has the CALL_PHONE permission.
1236 *
1237 * @throws SecurityException if the caller does not have the required permission
1238 */
1239 private void enforceCallPermission() {
1240 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1241 }
1242
Shishir Agrawal566b7612013-10-28 14:41:00 -07001243 /**
Gabriel Peal36ebb0d2014-03-20 09:20:43 -07001244 * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1245 *
1246 * @throws SecurityException if the caller does not have the required permission
1247 */
1248 private void enforcePrivilegedPhoneStatePermission() {
1249 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1250 null);
1251 }
1252
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001253 private String createTelUrl(String number) {
1254 if (TextUtils.isEmpty(number)) {
1255 return null;
1256 }
1257
Jake Hambye994d462014-02-03 13:10:13 -08001258 return "tel:" + number;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001259 }
1260
Ihab Awadf9e92732013-12-05 18:02:52 -08001261 private static void log(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001262 Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1263 }
1264
Ihab Awadf9e92732013-12-05 18:02:52 -08001265 private static void loge(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001266 Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1267 }
1268
1269 public int getActivePhoneType() {
Wink Saville36469e72014-06-11 15:17:00 -07001270 return getActivePhoneTypeUsingSubId(getDefaultSubscription());
1271 }
1272
1273 public int getActivePhoneTypeUsingSubId(long subId) {
1274 return getPhone(subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001275 }
1276
1277 /**
1278 * Returns the CDMA ERI icon index to display
1279 */
1280 public int getCdmaEriIconIndex() {
Wink Saville36469e72014-06-11 15:17:00 -07001281 return getCdmaEriIconIndexUsingSubId(getDefaultSubscription());
1282
1283 }
1284
1285 public int getCdmaEriIconIndexUsingSubId(long subId) {
1286 return getPhone(subId).getCdmaEriIconIndex();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001287 }
1288
1289 /**
1290 * Returns the CDMA ERI icon mode,
1291 * 0 - ON
1292 * 1 - FLASHING
1293 */
1294 public int getCdmaEriIconMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001295 return getCdmaEriIconModeUsingSubId(getDefaultSubscription());
1296 }
1297
1298 public int getCdmaEriIconModeUsingSubId(long subId) {
1299 return getPhone(subId).getCdmaEriIconMode();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001300 }
1301
1302 /**
1303 * Returns the CDMA ERI text,
1304 */
1305 public String getCdmaEriText() {
Wink Saville36469e72014-06-11 15:17:00 -07001306 return getCdmaEriTextUsingSubId(getDefaultSubscription());
1307 }
1308
1309 public String getCdmaEriTextUsingSubId(long subId) {
1310 return getPhone(subId).getCdmaEriText();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001311 }
1312
1313 /**
1314 * Returns true if CDMA provisioning needs to run.
1315 */
1316 public boolean needsOtaServiceProvisioning() {
1317 return mPhone.needsOtaServiceProvisioning();
1318 }
1319
1320 /**
1321 * Returns the unread count of voicemails
1322 */
1323 public int getVoiceMessageCount() {
Wink Saville36469e72014-06-11 15:17:00 -07001324 return getVoiceMessageCountUsingSubId(getDefaultSubscription());
1325 }
1326
1327 /**
1328 * Returns the unread count of voicemails for a subId
1329 */
1330 public int getVoiceMessageCountUsingSubId( long subId) {
1331 return getPhone(subId).getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001332 }
1333
1334 /**
1335 * Returns the data network type
1336 *
1337 * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1338 */
1339 @Override
1340 public int getNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001341 return getNetworkTypeUsingSubId(getDefaultSubscription());
1342 }
1343
1344 /**
1345 * Returns the network type for a subId
1346 */
1347 @Override
1348 public int getNetworkTypeUsingSubId(long subId) {
1349 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001350 }
1351
1352 /**
1353 * Returns the data network type
1354 */
1355 @Override
1356 public int getDataNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001357 return getDataNetworkTypeUsingSubId(getDefaultSubscription());
1358 }
1359
1360 /**
1361 * Returns the data network type for a subId
1362 */
1363 @Override
1364 public int getDataNetworkTypeUsingSubId(long subId) {
1365 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001366 }
1367
1368 /**
1369 * Returns the data network type
1370 */
1371 @Override
1372 public int getVoiceNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001373 return getVoiceNetworkTypeUsingSubId(getDefaultSubscription());
1374 }
1375
1376 /**
1377 * Returns the Voice network type for a subId
1378 */
1379 @Override
1380 public int getVoiceNetworkTypeUsingSubId(long subId) {
1381 return getPhone(subId).getServiceState().getVoiceNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001382 }
1383
1384 /**
1385 * @return true if a ICC card is present
1386 */
1387 public boolean hasIccCard() {
Wink Saville36469e72014-06-11 15:17:00 -07001388 // FIXME Make changes to pass defaultSimId of type int
1389 return hasIccCardUsingSlotId(getDefaultSubscription());
1390 }
1391
1392 /**
1393 * @return true if a ICC card is present for a slotId
1394 */
1395 public boolean hasIccCardUsingSlotId(long slotId) {
1396 return getPhone(slotId).getIccCard().hasIccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001397 }
1398
1399 /**
1400 * Return if the current radio is LTE on CDMA. This
1401 * is a tri-state return value as for a period of time
1402 * the mode may be unknown.
1403 *
1404 * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
Jake Hambye994d462014-02-03 13:10:13 -08001405 * or {@link Phone#LTE_ON_CDMA_TRUE}
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001406 */
1407 public int getLteOnCdmaMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001408 return getLteOnCdmaModeUsingSubId(getDefaultSubscription());
1409 }
1410
1411 public int getLteOnCdmaModeUsingSubId(long subId) {
1412 return getPhone(subId).getLteOnCdmaMode();
1413 }
1414
1415 public void setPhone(Phone phone) {
1416 mPhone = phone;
1417 }
1418
1419 /**
1420 * {@hide}
1421 * Returns Default subId, 0 in the case of single standby.
1422 */
1423 private long getDefaultSubscription() {
1424 return SubscriptionManager.getDefaultSubId();
1425 }
1426
1427 private long getPreferredVoiceSubscription() {
1428 return SubscriptionManager.getDefaultVoiceSubId();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001429 }
Ihab Awadf2177b72013-11-25 13:33:23 -08001430
1431 /**
1432 * @see android.telephony.TelephonyManager.WifiCallingChoices
1433 */
1434 public int getWhenToMakeWifiCalls() {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001435 return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1436 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
Ihab Awadf2177b72013-11-25 13:33:23 -08001437 }
1438
1439 /**
1440 * @see android.telephony.TelephonyManager.WifiCallingChoices
1441 */
1442 public void setWhenToMakeWifiCalls(int preference) {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001443 if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1444 Settings.System.putInt(mPhone.getContext().getContentResolver(),
1445 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
Ihab Awadf9e92732013-12-05 18:02:52 -08001446 }
1447
Sailesh Nepald1e68152013-12-12 19:08:02 -08001448 private static int getWhenToMakeWifiCallsDefaultPreference() {
1449 // TODO(sail): Use a build property to choose this value.
Evan Charlton9829e882013-12-19 15:30:38 -08001450 return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
Ihab Awadf2177b72013-11-25 13:33:23 -08001451 }
Shishir Agrawal69f68122013-12-16 17:25:49 -08001452
Shishir Agrawal566b7612013-10-28 14:41:00 -07001453 @Override
1454 public int iccOpenLogicalChannel(String AID) {
Junda Liua2e36012014-07-09 18:30:01 -07001455 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001456
1457 if (DBG) log("iccOpenLogicalChannel: " + AID);
1458 Integer channel = (Integer)sendRequest(CMD_OPEN_CHANNEL, AID);
1459 if (DBG) log("iccOpenLogicalChannel: " + channel);
Jake Hambye994d462014-02-03 13:10:13 -08001460 return channel;
Shishir Agrawal566b7612013-10-28 14:41:00 -07001461 }
1462
1463 @Override
1464 public boolean iccCloseLogicalChannel(int channel) {
Junda Liua2e36012014-07-09 18:30:01 -07001465 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001466
1467 if (DBG) log("iccCloseLogicalChannel: " + channel);
1468 if (channel < 0) {
1469 return false;
1470 }
Jake Hambye994d462014-02-03 13:10:13 -08001471 Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
Shishir Agrawal566b7612013-10-28 14:41:00 -07001472 if (DBG) log("iccCloseLogicalChannel: " + success);
1473 return success;
1474 }
1475
1476 @Override
1477 public String iccTransmitApduLogicalChannel(int channel, int cla,
1478 int command, int p1, int p2, int p3, String data) {
Junda Liua2e36012014-07-09 18:30:01 -07001479 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001480
1481 if (DBG) {
1482 log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1483 " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1484 " data=" + data);
1485 }
1486
1487 if (channel < 0) {
1488 return "";
1489 }
1490
1491 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU,
1492 new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1493 if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1494
1495 // If the payload is null, there was an error. Indicate that by returning
1496 // an empty string.
1497 if (response.payload == null) {
1498 return "";
1499 }
1500
1501 // Append the returned status code to the end of the response payload.
1502 String s = Integer.toHexString(
1503 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1504 s = IccUtils.bytesToHexString(response.payload) + s;
1505 return s;
1506 }
Jake Hambye994d462014-02-03 13:10:13 -08001507
Evan Charltonc66da362014-05-16 14:06:40 -07001508 @Override
1509 public String sendEnvelopeWithStatus(String content) {
Junda Liua2e36012014-07-09 18:30:01 -07001510 enforceModifyPermissionOrCarrierPrivilege();
Evan Charltonc66da362014-05-16 14:06:40 -07001511
1512 IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
1513 if (response.payload == null) {
1514 return "";
1515 }
1516
1517 // Append the returned status code to the end of the response payload.
1518 String s = Integer.toHexString(
1519 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1520 s = IccUtils.bytesToHexString(response.payload) + s;
1521 return s;
1522 }
1523
Jake Hambye994d462014-02-03 13:10:13 -08001524 /**
1525 * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1526 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1527 *
1528 * @param itemID the ID of the item to read
1529 * @return the NV item as a String, or null on error.
1530 */
1531 @Override
1532 public String nvReadItem(int itemID) {
Junda Liua2e36012014-07-09 18:30:01 -07001533 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001534 if (DBG) log("nvReadItem: item " + itemID);
1535 String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
1536 if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
1537 return value;
1538 }
1539
1540 /**
1541 * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1542 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1543 *
1544 * @param itemID the ID of the item to read
1545 * @param itemValue the value to write, as a String
1546 * @return true on success; false on any failure
1547 */
1548 @Override
1549 public boolean nvWriteItem(int itemID, String itemValue) {
Junda Liua2e36012014-07-09 18:30:01 -07001550 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001551 if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
1552 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
1553 new Pair<Integer, String>(itemID, itemValue));
1554 if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
1555 return success;
1556 }
1557
1558 /**
1559 * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
1560 * Used for device configuration by some CDMA operators.
1561 *
1562 * @param preferredRoamingList byte array containing the new PRL
1563 * @return true on success; false on any failure
1564 */
1565 @Override
1566 public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
Junda Liua2e36012014-07-09 18:30:01 -07001567 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001568 if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
1569 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
1570 if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
1571 return success;
1572 }
1573
1574 /**
1575 * Perform the specified type of NV config reset.
1576 * Used for device configuration by some CDMA operators.
1577 *
1578 * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
1579 * @return true on success; false on any failure
1580 */
1581 @Override
1582 public boolean nvResetConfig(int resetType) {
Junda Liua2e36012014-07-09 18:30:01 -07001583 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001584 if (DBG) log("nvResetConfig: type " + resetType);
1585 Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
1586 if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
1587 return success;
1588 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001589
1590 /**
Wink Saville36469e72014-06-11 15:17:00 -07001591 * {@hide}
1592 * Returns Default sim, 0 in the case of single standby.
1593 */
1594 public int getDefaultSim() {
1595 //TODO Need to get it from Telephony Devcontroller
1596 return 0;
1597 }
1598
ram87fca6f2014-07-18 18:58:44 +05301599 public String[] getPcscfAddress(String apnType) {
Wink Saville36469e72014-06-11 15:17:00 -07001600 enforceReadPermission();
ram87fca6f2014-07-18 18:58:44 +05301601 return mPhone.getPcscfAddress(apnType);
Wink Saville36469e72014-06-11 15:17:00 -07001602 }
1603
1604 public void setImsRegistrationState(boolean registered) {
1605 enforceModifyPermission();
1606 mPhone.setImsRegistrationState(registered);
1607 }
1608
1609 /**
Junda Liu84d15a22014-07-02 11:21:04 -07001610 * Get the calculated preferred network type.
1611 * Used for debugging incorrect network type.
1612 *
1613 * @return the preferred network type, defined in RILConstants.java.
1614 */
1615 @Override
1616 public int getCalculatedPreferredNetworkType() {
1617 enforceReadPermission();
1618 return PhoneFactory.calculatePreferredNetworkType(mPhone.getContext());
1619 }
1620
1621 /**
Jake Hamby7c27be32014-03-03 13:25:59 -08001622 * Get the preferred network type.
1623 * Used for device configuration by some CDMA operators.
1624 *
1625 * @return the preferred network type, defined in RILConstants.java.
1626 */
1627 @Override
1628 public int getPreferredNetworkType() {
Junda Liua2e36012014-07-09 18:30:01 -07001629 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001630 if (DBG) log("getPreferredNetworkType");
1631 int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null);
1632 int networkType = (result != null ? result[0] : -1);
1633 if (DBG) log("getPreferredNetworkType: " + networkType);
1634 return networkType;
1635 }
1636
1637 /**
1638 * Set the preferred network type.
1639 * Used for device configuration by some CDMA operators.
1640 *
1641 * @param networkType the preferred network type, defined in RILConstants.java.
1642 * @return true on success; false on any failure.
1643 */
1644 @Override
1645 public boolean setPreferredNetworkType(int networkType) {
Junda Liua2e36012014-07-09 18:30:01 -07001646 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001647 if (DBG) log("setPreferredNetworkType: type " + networkType);
1648 Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType);
1649 if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
Junda Liu80bc0d12014-07-14 16:36:44 -07001650 if (success) {
1651 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1652 Settings.Global.PREFERRED_NETWORK_MODE, networkType);
1653 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001654 return success;
1655 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001656
1657 /**
Junda Liu787bc7e2014-06-30 13:38:02 -07001658 * Set the CDMA subscription source.
1659 * Used for device supporting both NV and RUIM for CDMA.
1660 *
1661 * @param subscriptionType the subscription type, 0 for RUIM, 1 for NV.
1662 * @return true on success; false on any failure.
1663 */
1664 @Override
1665 public boolean setCdmaSubscription(int subscriptionType) {
Junda Liua2e36012014-07-09 18:30:01 -07001666 enforceModifyPermissionOrCarrierPrivilege();
Junda Liu787bc7e2014-06-30 13:38:02 -07001667 if (DBG) log("setCdmaSubscription: type " + subscriptionType);
1668 if (subscriptionType != mPhone.CDMA_SUBSCRIPTION_RUIM_SIM &&
1669 subscriptionType != mPhone.CDMA_SUBSCRIPTION_NV) {
1670 loge("setCdmaSubscription: unsupported subscriptionType.");
1671 return false;
1672 }
1673 Boolean success = (Boolean) sendRequest(CMD_SET_CDMA_SUBSCRIPTION, subscriptionType);
1674 if (DBG) log("setCdmaSubscription: " + (success ? "ok" : "fail"));
1675 if (success) {
1676 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1677 Settings.Global.CDMA_SUBSCRIPTION_MODE, subscriptionType);
1678 }
1679 return success;
1680 }
1681
1682 /**
Robert Greenwalted86e582014-05-21 20:03:20 -07001683 * Set mobile data enabled
1684 * Used by the user through settings etc to turn on/off mobile data
1685 *
1686 * @param enable {@code true} turn turn data on, else {@code false}
1687 */
1688 @Override
1689 public void setDataEnabled(boolean enable) {
1690 enforceModifyPermission();
1691 mPhone.setDataEnabled(enable);
1692 }
1693
1694 /**
Robert Greenwalt646120a2014-05-23 11:54:03 -07001695 * Get whether mobile data is enabled.
1696 *
1697 * Note that this used to be available from ConnectivityService, gated by
1698 * ACCESS_NETWORK_STATE permission, so this will accept either that or
1699 * our MODIFY_PHONE_STATE.
Robert Greenwalted86e582014-05-21 20:03:20 -07001700 *
1701 * @return {@code true} if data is enabled else {@code false}
1702 */
1703 @Override
1704 public boolean getDataEnabled() {
Robert Greenwalt646120a2014-05-23 11:54:03 -07001705 try {
1706 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
1707 null);
1708 } catch (Exception e) {
1709 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
1710 null);
1711 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001712 return mPhone.getDataEnabled();
1713 }
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001714
1715 @Override
1716 public int hasCarrierPrivileges() {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001717 UiccCard card = UiccController.getInstance().getUiccCard();
1718 if (card == null) {
1719 loge("hasCarrierPrivileges: No UICC");
1720 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1721 }
1722 return card.getCarrierPrivilegeStatusForCurrentTransaction(
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001723 mPhone.getContext().getPackageManager());
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001724 }
Junda Liu29340342014-07-10 15:23:27 -07001725
1726 @Override
Shishir Agrawal6d5a2852014-07-11 16:32:57 -07001727 public int checkCarrierPrivilegesForPackage(String pkgname) {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001728 UiccCard card = UiccController.getInstance().getUiccCard();
1729 if (card == null) {
1730 loge("checkCarrierPrivilegesForPackage: No UICC");
1731 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1732 }
1733 return card.getCarrierPrivilegeStatus(mPhone.getContext().getPackageManager(), pkgname);
Junda Liu29340342014-07-10 15:23:27 -07001734 }
Derek Tan89e89d42014-07-08 17:00:10 -07001735
1736 @Override
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001737 public List<String> getCarrierPackageNamesForBroadcastIntent(Intent intent) {
1738 UiccCard card = UiccController.getInstance().getUiccCard();
1739 if (card == null) {
1740 loge("getCarrierPackageNamesForBroadcastIntent: No UICC");
1741 return null ;
1742 }
1743 return card.getCarrierPackageNamesForBroadcastIntent(
1744 mPhone.getContext().getPackageManager(), intent);
1745 }
1746
1747 @Override
Derek Tan89e89d42014-07-08 17:00:10 -07001748 public void enableSimplifiedNetworkSettings(long subId, boolean enable) {
Derek Tan352d8cd2014-07-12 12:57:11 -07001749 enforceModifyPermissionOrCarrierPrivilege();
Derek Tan89e89d42014-07-08 17:00:10 -07001750 if (enable) {
1751 mSimplifiedNetworkSettings.add(subId);
1752 } else {
1753 mSimplifiedNetworkSettings.remove(subId);
1754 }
1755 }
1756
1757 @Override
1758 public boolean getSimplifiedNetworkSettingsEnabled(long subId) {
1759 enforceReadPermission();
1760 return mSimplifiedNetworkSettings.contains(subId);
1761 }
Derek Tan7226c842014-07-02 17:42:23 -07001762
1763 @Override
1764 public void setLine1NumberForDisplay(long subId, String alphaTag, String number) {
Derek Tan352d8cd2014-07-12 12:57:11 -07001765 enforceModifyPermissionOrCarrierPrivilege();
Derek Tan7226c842014-07-02 17:42:23 -07001766 mAdnRecordsForDisplay.put(subId, new AdnRecord(alphaTag, number));
1767 }
1768
1769 @Override
1770 public String getLine1NumberForDisplay(long subId) {
1771 enforceReadPermission();
1772 if (!mAdnRecordsForDisplay.containsKey(subId)) {
1773 return null;
1774 }
1775 AdnRecord adnRecord = mAdnRecordsForDisplay.get(subId);
1776 if (adnRecord.getNumber() == null || adnRecord.getNumber().isEmpty()) {
1777 return null;
1778 }
1779 return adnRecord.getNumber();
1780 }
1781
1782 @Override
1783 public String getLine1AlphaTagForDisplay(long subId) {
1784 enforceReadPermission();
1785 if (!mAdnRecordsForDisplay.containsKey(subId)) {
1786 return null;
1787 }
1788 AdnRecord adnRecord = mAdnRecordsForDisplay.get(subId);
1789 if (adnRecord.getAlphaTag() == null || adnRecord.getAlphaTag().isEmpty()) {
1790 return null;
1791 }
1792 return adnRecord.getAlphaTag();
1793 }
Shishir Agrawalb1ebf8c2014-07-17 16:32:41 -07001794
1795 @Override
1796 public boolean setOperatorBrandOverride(String iccId, String brand) {
1797 enforceModifyPermissionOrCarrierPrivilege();
1798 return mPhone.setOperatorBrandOverride(iccId, brand);
1799 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001800}