blob: d8259a3f092ca5e1b8caddc54b87da4250ac5962 [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;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -070042import android.telephony.IccOpenLogicalChannelResponse;
Jake Hambye994d462014-02-03 13:10:13 -080043import android.telephony.NeighboringCellInfo;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070044import android.telephony.ServiceState;
Wink Saville36469e72014-06-11 15:17:00 -070045import android.telephony.SubscriptionManager;
Ihab Awadf2177b72013-11-25 13:33:23 -080046import android.telephony.TelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070047import android.text.TextUtils;
48import android.util.Log;
Jake Hambye994d462014-02-03 13:10:13 -080049import android.util.Pair;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070050
Shishir Agrawal566b7612013-10-28 14:41:00 -070051import com.android.internal.telephony.CallManager;
52import com.android.internal.telephony.CommandException;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070053import com.android.internal.telephony.Connection;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070054import com.android.internal.telephony.DefaultPhoneNotifier;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070055import com.android.internal.telephony.ITelephony;
Jake Hambye994d462014-02-03 13:10:13 -080056import com.android.internal.telephony.IccCard;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070057import com.android.internal.telephony.Phone;
Wink Saville36469e72014-06-11 15:17:00 -070058import com.android.internal.telephony.PhoneFactory;
59import com.android.internal.telephony.CallManager;
60import com.android.internal.telephony.CommandException;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070061import com.android.internal.telephony.PhoneConstants;
Wink Saville36469e72014-06-11 15:17:00 -070062import com.android.internal.telephony.dataconnection.DctController;
Derek Tan7226c842014-07-02 17:42:23 -070063import com.android.internal.telephony.uicc.AdnRecord;
Shishir Agrawal566b7612013-10-28 14:41:00 -070064import com.android.internal.telephony.uicc.IccIoResult;
65import com.android.internal.telephony.uicc.IccUtils;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -070066import com.android.internal.telephony.uicc.UiccCard;
Shishir Agrawal60f9c952014-06-23 12:00:43 -070067import com.android.internal.telephony.uicc.UiccCarrierPrivilegeRules;
Shishir Agrawal566b7612013-10-28 14:41:00 -070068import com.android.internal.telephony.uicc.UiccController;
Jake Hambye994d462014-02-03 13:10:13 -080069import com.android.internal.util.HexDump;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070070
Wink Saville36469e72014-06-11 15:17:00 -070071import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
72
Santos Cordon7d4ddf62013-07-10 11:58:08 -070073import java.util.ArrayList;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070074import java.util.HashMap;
Derek Tan89e89d42014-07-08 17:00:10 -070075import java.util.HashSet;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070076import java.util.Iterator;
Jake Hambye994d462014-02-03 13:10:13 -080077import java.util.List;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070078import java.util.Map;
Derek Tan89e89d42014-07-08 17:00:10 -070079import java.util.Set;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070080
81/**
82 * Implementation of the ITelephony interface.
83 */
Santos Cordon117fee72014-05-16 17:56:12 -070084public class PhoneInterfaceManager extends ITelephony.Stub {
Santos Cordon7d4ddf62013-07-10 11:58:08 -070085 private static final String LOG_TAG = "PhoneInterfaceManager";
86 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
87 private static final boolean DBG_LOC = false;
88
89 // Message codes used with mMainThreadHandler
90 private static final int CMD_HANDLE_PIN_MMI = 1;
91 private static final int CMD_HANDLE_NEIGHBORING_CELL = 2;
92 private static final int EVENT_NEIGHBORING_CELL_DONE = 3;
93 private static final int CMD_ANSWER_RINGING_CALL = 4;
94 private static final int CMD_END_CALL = 5; // not used yet
95 private static final int CMD_SILENCE_RINGER = 6;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -070096 private static final int CMD_TRANSMIT_APDU_LOGICAL_CHANNEL = 7;
97 private static final int EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE = 8;
Shishir Agrawal566b7612013-10-28 14:41:00 -070098 private static final int CMD_OPEN_CHANNEL = 9;
99 private static final int EVENT_OPEN_CHANNEL_DONE = 10;
100 private static final int CMD_CLOSE_CHANNEL = 11;
101 private static final int EVENT_CLOSE_CHANNEL_DONE = 12;
Jake Hambye994d462014-02-03 13:10:13 -0800102 private static final int CMD_NV_READ_ITEM = 13;
103 private static final int EVENT_NV_READ_ITEM_DONE = 14;
104 private static final int CMD_NV_WRITE_ITEM = 15;
105 private static final int EVENT_NV_WRITE_ITEM_DONE = 16;
106 private static final int CMD_NV_WRITE_CDMA_PRL = 17;
107 private static final int EVENT_NV_WRITE_CDMA_PRL_DONE = 18;
108 private static final int CMD_NV_RESET_CONFIG = 19;
109 private static final int EVENT_NV_RESET_CONFIG_DONE = 20;
Jake Hamby7c27be32014-03-03 13:25:59 -0800110 private static final int CMD_GET_PREFERRED_NETWORK_TYPE = 21;
111 private static final int EVENT_GET_PREFERRED_NETWORK_TYPE_DONE = 22;
112 private static final int CMD_SET_PREFERRED_NETWORK_TYPE = 23;
113 private static final int EVENT_SET_PREFERRED_NETWORK_TYPE_DONE = 24;
Sailesh Nepal35b59452014-03-06 09:26:56 -0800114 private static final int CMD_SEND_ENVELOPE = 25;
115 private static final int EVENT_SEND_ENVELOPE_DONE = 26;
Junda Liu787bc7e2014-06-30 13:38:02 -0700116 private static final int CMD_SET_CDMA_SUBSCRIPTION = 27;
117 private static final int EVENT_SET_CDMA_SUBSCRIPTION_DONE = 28;
Steven Liu4bf01bc2014-07-17 11:05:29 -0500118 private static final int CMD_INVOKE_OEM_RIL_REQUEST_RAW = 29;
119 private static final int EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE = 30;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700120 private static final int CMD_TRANSMIT_APDU_BASIC_CHANNEL = 31;
121 private static final int EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE = 32;
122 private static final int CMD_EXCHANGE_SIM_IO = 33;
123 private static final int EVENT_EXCHANGE_SIM_IO_DONE = 34;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700124
125 /** The singleton instance. */
126 private static PhoneInterfaceManager sInstance;
127
128 PhoneGlobals mApp;
129 Phone mPhone;
130 CallManager mCM;
131 AppOpsManager mAppOps;
132 MainThreadHandler mMainThreadHandler;
133
134 /**
Derek Tan89e89d42014-07-08 17:00:10 -0700135 * Indicates if Android should display a simplified Mobile Network Settings UI in a specific
136 * subscription.
137 */
138 Set<Long> mSimplifiedNetworkSettings;
Derek Tan7226c842014-07-02 17:42:23 -0700139 Map<Long, AdnRecord> mAdnRecordsForDisplay;
Derek Tan89e89d42014-07-08 17:00:10 -0700140
141 /**
Shishir Agrawal566b7612013-10-28 14:41:00 -0700142 * A request object to use for transmitting data to an ICC.
143 */
144 private static final class IccAPDUArgument {
145 public int channel, cla, command, p1, p2, p3;
146 public String data;
147
148 public IccAPDUArgument(int channel, int cla, int command,
149 int p1, int p2, int p3, String data) {
150 this.channel = channel;
151 this.cla = cla;
152 this.command = command;
153 this.p1 = p1;
154 this.p2 = p2;
155 this.p3 = p3;
156 this.data = data;
157 }
158 }
159
160 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700161 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
162 * request after sending. The main thread will notify the request when it is complete.
163 */
164 private static final class MainThreadRequest {
165 /** The argument to use for the request */
166 public Object argument;
167 /** The result of the request that is run on the main thread */
168 public Object result;
169
170 public MainThreadRequest(Object argument) {
171 this.argument = argument;
172 }
173 }
174
Sailesh Nepalcc0375f2013-11-13 09:15:18 -0800175 private static final class IncomingThirdPartyCallArgs {
176 public final ComponentName component;
177 public final String callId;
178 public final String callerDisplayName;
179
180 public IncomingThirdPartyCallArgs(ComponentName component, String callId,
181 String callerDisplayName) {
182 this.component = component;
183 this.callId = callId;
184 this.callerDisplayName = callerDisplayName;
185 }
186 }
187
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700188 /**
189 * A handler that processes messages on the main thread in the phone process. Since many
190 * of the Phone calls are not thread safe this is needed to shuttle the requests from the
191 * inbound binder threads to the main thread in the phone process. The Binder thread
192 * may provide a {@link MainThreadRequest} object in the msg.obj field that they are waiting
193 * on, which will be notified when the operation completes and will contain the result of the
194 * request.
195 *
196 * <p>If a MainThreadRequest object is provided in the msg.obj field,
197 * note that request.result must be set to something non-null for the calling thread to
198 * unblock.
199 */
200 private final class MainThreadHandler extends Handler {
201 @Override
202 public void handleMessage(Message msg) {
203 MainThreadRequest request;
204 Message onCompleted;
205 AsyncResult ar;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700206 UiccCard uiccCard = UiccController.getInstance().getUiccCard();
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700207 IccAPDUArgument iccArgument;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700208
209 switch (msg.what) {
210 case CMD_HANDLE_PIN_MMI:
211 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800212 request.result = mPhone.handlePinMmi((String) request.argument);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700213 // Wake up the requesting thread
214 synchronized (request) {
215 request.notifyAll();
216 }
217 break;
218
219 case CMD_HANDLE_NEIGHBORING_CELL:
220 request = (MainThreadRequest) msg.obj;
221 onCompleted = obtainMessage(EVENT_NEIGHBORING_CELL_DONE,
222 request);
223 mPhone.getNeighboringCids(onCompleted);
224 break;
225
226 case EVENT_NEIGHBORING_CELL_DONE:
227 ar = (AsyncResult) msg.obj;
228 request = (MainThreadRequest) ar.userObj;
229 if (ar.exception == null && ar.result != null) {
230 request.result = ar.result;
231 } else {
232 // create an empty list to notify the waiting thread
Jake Hambye994d462014-02-03 13:10:13 -0800233 request.result = new ArrayList<NeighboringCellInfo>(0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700234 }
235 // Wake up the requesting thread
236 synchronized (request) {
237 request.notifyAll();
238 }
239 break;
240
241 case CMD_ANSWER_RINGING_CALL:
242 answerRingingCallInternal();
243 break;
244
245 case CMD_SILENCE_RINGER:
246 silenceRingerInternal();
247 break;
248
249 case CMD_END_CALL:
250 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800251 boolean hungUp;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700252 int phoneType = mPhone.getPhoneType();
253 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
254 // CDMA: If the user presses the Power button we treat it as
255 // ending the complete call session
256 hungUp = PhoneUtils.hangupRingingAndActive(mPhone);
257 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
258 // GSM: End the call as per the Phone state
259 hungUp = PhoneUtils.hangup(mCM);
260 } else {
261 throw new IllegalStateException("Unexpected phone type: " + phoneType);
262 }
263 if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up"));
264 request.result = hungUp;
265 // Wake up the requesting thread
266 synchronized (request) {
267 request.notifyAll();
268 }
269 break;
270
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700271 case CMD_TRANSMIT_APDU_LOGICAL_CHANNEL:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700272 request = (MainThreadRequest) msg.obj;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700273 iccArgument = (IccAPDUArgument) request.argument;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700274 if (uiccCard == null) {
275 loge("iccTransmitApduLogicalChannel: No UICC");
276 request.result = new IccIoResult(0x6F, 0, (byte[])null);
277 synchronized (request) {
278 request.notifyAll();
279 }
280 } else {
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700281 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE,
282 request);
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700283 uiccCard.iccTransmitApduLogicalChannel(
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700284 iccArgument.channel, iccArgument.cla, iccArgument.command,
285 iccArgument.p1, iccArgument.p2, iccArgument.p3, iccArgument.data,
Shishir Agrawal566b7612013-10-28 14:41:00 -0700286 onCompleted);
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700287 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700288 break;
289
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700290 case EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700291 ar = (AsyncResult) msg.obj;
292 request = (MainThreadRequest) ar.userObj;
293 if (ar.exception == null && ar.result != null) {
294 request.result = ar.result;
295 } else {
296 request.result = new IccIoResult(0x6F, 0, (byte[])null);
297 if (ar.result == null) {
298 loge("iccTransmitApduLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800299 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700300 loge("iccTransmitApduLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800301 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700302 } else {
303 loge("iccTransmitApduLogicalChannel: Unknown exception");
304 }
305 }
306 synchronized (request) {
307 request.notifyAll();
308 }
309 break;
310
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700311 case CMD_TRANSMIT_APDU_BASIC_CHANNEL:
312 request = (MainThreadRequest) msg.obj;
313 iccArgument = (IccAPDUArgument) request.argument;
314 if (uiccCard == null) {
315 loge("iccTransmitApduBasicChannel: No UICC");
316 request.result = new IccIoResult(0x6F, 0, (byte[])null);
317 synchronized (request) {
318 request.notifyAll();
319 }
320 } else {
321 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE,
322 request);
323 uiccCard.iccTransmitApduBasicChannel(
324 iccArgument.cla, iccArgument.command, iccArgument.p1, iccArgument.p2,
325 iccArgument.p3, iccArgument.data, onCompleted);
326 }
327 break;
328
329 case EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE:
330 ar = (AsyncResult) msg.obj;
331 request = (MainThreadRequest) ar.userObj;
332 if (ar.exception == null && ar.result != null) {
333 request.result = ar.result;
334 } else {
335 request.result = new IccIoResult(0x6F, 0, (byte[])null);
336 if (ar.result == null) {
337 loge("iccTransmitApduBasicChannel: Empty response");
338 } else if (ar.exception instanceof CommandException) {
339 loge("iccTransmitApduBasicChannel: CommandException: " +
340 ar.exception);
341 } else {
342 loge("iccTransmitApduBasicChannel: Unknown exception");
343 }
344 }
345 synchronized (request) {
346 request.notifyAll();
347 }
348 break;
349
350 case CMD_EXCHANGE_SIM_IO:
351 request = (MainThreadRequest) msg.obj;
352 iccArgument = (IccAPDUArgument) request.argument;
353 if (uiccCard == null) {
354 loge("iccExchangeSimIO: No UICC");
355 request.result = new IccIoResult(0x6F, 0, (byte[])null);
356 synchronized (request) {
357 request.notifyAll();
358 }
359 } else {
360 onCompleted = obtainMessage(EVENT_EXCHANGE_SIM_IO_DONE,
361 request);
362 uiccCard.iccExchangeSimIO(iccArgument.cla, /* fileID */
363 iccArgument.command, iccArgument.p1, iccArgument.p2, iccArgument.p3,
364 iccArgument.data, onCompleted);
365 }
366 break;
367
368 case EVENT_EXCHANGE_SIM_IO_DONE:
369 ar = (AsyncResult) msg.obj;
370 request = (MainThreadRequest) ar.userObj;
371 if (ar.exception == null && ar.result != null) {
372 request.result = ar.result;
373 } else {
374 request.result = new IccIoResult(0x6f, 0, (byte[])null);
375 }
376 synchronized (request) {
377 request.notifyAll();
378 }
379 break;
380
Derek Tan4d5e5c12014-02-04 11:54:58 -0800381 case CMD_SEND_ENVELOPE:
382 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700383 if (uiccCard == null) {
384 loge("sendEnvelopeWithStatus: No UICC");
385 request.result = new IccIoResult(0x6F, 0, (byte[])null);
386 synchronized (request) {
387 request.notifyAll();
388 }
389 } else {
390 onCompleted = obtainMessage(EVENT_SEND_ENVELOPE_DONE, request);
391 uiccCard.sendEnvelopeWithStatus((String)request.argument, onCompleted);
392 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800393 break;
394
395 case EVENT_SEND_ENVELOPE_DONE:
396 ar = (AsyncResult) msg.obj;
397 request = (MainThreadRequest) ar.userObj;
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700398 if (ar.exception == null && ar.result != null) {
399 request.result = ar.result;
Derek Tan4d5e5c12014-02-04 11:54:58 -0800400 } else {
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700401 request.result = new IccIoResult(0x6F, 0, (byte[])null);
402 if (ar.result == null) {
403 loge("sendEnvelopeWithStatus: Empty response");
404 } else if (ar.exception instanceof CommandException) {
405 loge("sendEnvelopeWithStatus: CommandException: " +
406 ar.exception);
407 } else {
408 loge("sendEnvelopeWithStatus: exception:" + ar.exception);
409 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800410 }
411 synchronized (request) {
412 request.notifyAll();
413 }
414 break;
415
Shishir Agrawal566b7612013-10-28 14:41:00 -0700416 case CMD_OPEN_CHANNEL:
417 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700418 if (uiccCard == null) {
419 loge("iccOpenLogicalChannel: No UICC");
420 request.result = new IccIoResult(0x6F, 0, (byte[])null);
421 synchronized (request) {
422 request.notifyAll();
423 }
424 } else {
425 onCompleted = obtainMessage(EVENT_OPEN_CHANNEL_DONE, request);
426 uiccCard.iccOpenLogicalChannel((String)request.argument, onCompleted);
427 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700428 break;
429
430 case EVENT_OPEN_CHANNEL_DONE:
431 ar = (AsyncResult) msg.obj;
432 request = (MainThreadRequest) ar.userObj;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700433 IccOpenLogicalChannelResponse openChannelResp;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700434 if (ar.exception == null && ar.result != null) {
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700435 int[] result = (int[]) ar.result;
436 int channelId = result[0];
437 byte[] selectResponse = null;
438 if (result.length > 1) {
439 selectResponse = new byte[result.length - 1];
440 for (int i = 1; i < result.length; ++i) {
441 selectResponse[i - 1] = (byte) result[i];
442 }
443 }
444 openChannelResp = new IccOpenLogicalChannelResponse(channelId,
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700445 IccOpenLogicalChannelResponse.STATUS_NO_ERROR, selectResponse);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700446 } else {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700447 if (ar.result == null) {
448 loge("iccOpenLogicalChannel: Empty response");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700449 }
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700450 if (ar.exception != null) {
451 loge("iccOpenLogicalChannel: Exception: " + ar.exception);
452 }
453
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700454 int errorCode = IccOpenLogicalChannelResponse.STATUS_UNKNOWN_ERROR;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700455 if ((ar.exception != null) && (ar.exception instanceof CommandException)) {
456 if (ar.exception.getMessage().compareTo("MISSING_RESOURCE") == 0) {
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700457 errorCode = IccOpenLogicalChannelResponse.STATUS_MISSING_RESOURCE;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700458 } else if (ar.exception.getMessage().compareTo("NO_SUCH_ELEMENT") == 0) {
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700459 errorCode = IccOpenLogicalChannelResponse.STATUS_NO_SUCH_ELEMENT;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700460 }
461 }
462 openChannelResp = new IccOpenLogicalChannelResponse(
463 IccOpenLogicalChannelResponse.INVALID_CHANNEL, errorCode, null);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700464 }
Shishir Agrawal82c8a462014-07-31 18:13:17 -0700465 request.result = openChannelResp;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700466 synchronized (request) {
467 request.notifyAll();
468 }
469 break;
470
471 case CMD_CLOSE_CHANNEL:
472 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700473 if (uiccCard == null) {
474 loge("iccCloseLogicalChannel: No UICC");
475 request.result = new IccIoResult(0x6F, 0, (byte[])null);
476 synchronized (request) {
477 request.notifyAll();
478 }
479 } else {
480 onCompleted = obtainMessage(EVENT_CLOSE_CHANNEL_DONE, request);
481 uiccCard.iccCloseLogicalChannel((Integer) request.argument, onCompleted);
482 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700483 break;
484
485 case EVENT_CLOSE_CHANNEL_DONE:
Jake Hambye994d462014-02-03 13:10:13 -0800486 handleNullReturnEvent(msg, "iccCloseLogicalChannel");
487 break;
488
489 case CMD_NV_READ_ITEM:
490 request = (MainThreadRequest) msg.obj;
491 onCompleted = obtainMessage(EVENT_NV_READ_ITEM_DONE, request);
492 mPhone.nvReadItem((Integer) request.argument, onCompleted);
493 break;
494
495 case EVENT_NV_READ_ITEM_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700496 ar = (AsyncResult) msg.obj;
497 request = (MainThreadRequest) ar.userObj;
Jake Hambye994d462014-02-03 13:10:13 -0800498 if (ar.exception == null && ar.result != null) {
499 request.result = ar.result; // String
Shishir Agrawal566b7612013-10-28 14:41:00 -0700500 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800501 request.result = "";
502 if (ar.result == null) {
503 loge("nvReadItem: Empty response");
504 } else if (ar.exception instanceof CommandException) {
505 loge("nvReadItem: CommandException: " +
506 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700507 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800508 loge("nvReadItem: Unknown exception");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700509 }
510 }
511 synchronized (request) {
512 request.notifyAll();
513 }
514 break;
515
Jake Hambye994d462014-02-03 13:10:13 -0800516 case CMD_NV_WRITE_ITEM:
517 request = (MainThreadRequest) msg.obj;
518 onCompleted = obtainMessage(EVENT_NV_WRITE_ITEM_DONE, request);
519 Pair<Integer, String> idValue = (Pair<Integer, String>) request.argument;
520 mPhone.nvWriteItem(idValue.first, idValue.second, onCompleted);
521 break;
522
523 case EVENT_NV_WRITE_ITEM_DONE:
524 handleNullReturnEvent(msg, "nvWriteItem");
525 break;
526
527 case CMD_NV_WRITE_CDMA_PRL:
528 request = (MainThreadRequest) msg.obj;
529 onCompleted = obtainMessage(EVENT_NV_WRITE_CDMA_PRL_DONE, request);
530 mPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
531 break;
532
533 case EVENT_NV_WRITE_CDMA_PRL_DONE:
534 handleNullReturnEvent(msg, "nvWriteCdmaPrl");
535 break;
536
537 case CMD_NV_RESET_CONFIG:
538 request = (MainThreadRequest) msg.obj;
539 onCompleted = obtainMessage(EVENT_NV_RESET_CONFIG_DONE, request);
540 mPhone.nvResetConfig((Integer) request.argument, onCompleted);
541 break;
542
543 case EVENT_NV_RESET_CONFIG_DONE:
544 handleNullReturnEvent(msg, "nvResetConfig");
545 break;
546
Jake Hamby7c27be32014-03-03 13:25:59 -0800547 case CMD_GET_PREFERRED_NETWORK_TYPE:
548 request = (MainThreadRequest) msg.obj;
549 onCompleted = obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE_DONE, request);
550 mPhone.getPreferredNetworkType(onCompleted);
551 break;
552
553 case EVENT_GET_PREFERRED_NETWORK_TYPE_DONE:
554 ar = (AsyncResult) msg.obj;
555 request = (MainThreadRequest) ar.userObj;
556 if (ar.exception == null && ar.result != null) {
557 request.result = ar.result; // Integer
558 } else {
559 request.result = -1;
560 if (ar.result == null) {
561 loge("getPreferredNetworkType: Empty response");
562 } else if (ar.exception instanceof CommandException) {
563 loge("getPreferredNetworkType: CommandException: " +
564 ar.exception);
565 } else {
566 loge("getPreferredNetworkType: Unknown exception");
567 }
568 }
569 synchronized (request) {
570 request.notifyAll();
571 }
572 break;
573
574 case CMD_SET_PREFERRED_NETWORK_TYPE:
575 request = (MainThreadRequest) msg.obj;
576 onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);
577 int networkType = (Integer) request.argument;
578 mPhone.setPreferredNetworkType(networkType, onCompleted);
579 break;
580
581 case EVENT_SET_PREFERRED_NETWORK_TYPE_DONE:
582 handleNullReturnEvent(msg, "setPreferredNetworkType");
583 break;
584
Junda Liu787bc7e2014-06-30 13:38:02 -0700585 case CMD_SET_CDMA_SUBSCRIPTION:
586 request = (MainThreadRequest) msg.obj;
587 onCompleted = obtainMessage(EVENT_SET_CDMA_SUBSCRIPTION_DONE, request);
588 int subscriptionType = (Integer) request.argument;
589 mPhone.setCdmaSubscription(subscriptionType, onCompleted);
590 break;
591
592 case EVENT_SET_CDMA_SUBSCRIPTION_DONE:
593 handleNullReturnEvent(msg, "setCdmaSubscription");
594 break;
595
Steven Liu4bf01bc2014-07-17 11:05:29 -0500596 case CMD_INVOKE_OEM_RIL_REQUEST_RAW:
597 request = (MainThreadRequest)msg.obj;
598 onCompleted = obtainMessage(EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE, request);
599 mPhone.invokeOemRilRequestRaw((byte[])request.argument, onCompleted);
600 break;
601
602 case EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE:
603 ar = (AsyncResult)msg.obj;
604 request = (MainThreadRequest)ar.userObj;
605 request.result = ar;
606 synchronized (request) {
607 request.notifyAll();
608 }
609 break;
610
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700611 default:
612 Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
613 break;
614 }
615 }
Jake Hambye994d462014-02-03 13:10:13 -0800616
617 private void handleNullReturnEvent(Message msg, String command) {
618 AsyncResult ar = (AsyncResult) msg.obj;
619 MainThreadRequest request = (MainThreadRequest) ar.userObj;
620 if (ar.exception == null) {
621 request.result = true;
622 } else {
623 request.result = false;
624 if (ar.exception instanceof CommandException) {
625 loge(command + ": CommandException: " + ar.exception);
626 } else {
627 loge(command + ": Unknown exception");
628 }
629 }
630 synchronized (request) {
631 request.notifyAll();
632 }
633 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700634 }
635
636 /**
637 * Posts the specified command to be executed on the main thread,
638 * waits for the request to complete, and returns the result.
639 * @see #sendRequestAsync
640 */
641 private Object sendRequest(int command, Object argument) {
Santos Cordon500b0e02014-06-17 10:33:33 -0700642 return sendRequest(command, argument, null);
Wink Saville36469e72014-06-11 15:17:00 -0700643 }
644
645 /**
646 * Posts the specified command to be executed on the main thread,
647 * waits for the request to complete, and returns the result.
648 * @see #sendRequestAsync
649 */
650 private Object sendRequest(int command, Object argument, Object argument2) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700651 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
652 throw new RuntimeException("This method will deadlock if called from the main thread.");
653 }
654
655 MainThreadRequest request = new MainThreadRequest(argument);
656 Message msg = mMainThreadHandler.obtainMessage(command, request);
657 msg.sendToTarget();
658
659 // Wait for the request to complete
660 synchronized (request) {
661 while (request.result == null) {
662 try {
663 request.wait();
664 } catch (InterruptedException e) {
665 // Do nothing, go back and wait until the request is complete
666 }
667 }
668 }
669 return request.result;
670 }
671
672 /**
673 * Asynchronous ("fire and forget") version of sendRequest():
674 * Posts the specified command to be executed on the main thread, and
675 * returns immediately.
676 * @see #sendRequest
677 */
678 private void sendRequestAsync(int command) {
679 mMainThreadHandler.sendEmptyMessage(command);
680 }
681
682 /**
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -0700683 * Same as {@link #sendRequestAsync(int)} except it takes an argument.
684 * @see {@link #sendRequest(int,Object)}
685 */
686 private void sendRequestAsync(int command, Object argument) {
687 MainThreadRequest request = new MainThreadRequest(argument);
688 Message msg = mMainThreadHandler.obtainMessage(command, request);
689 msg.sendToTarget();
690 }
691
692 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700693 * Initialize the singleton PhoneInterfaceManager instance.
694 * This is only done once, at startup, from PhoneApp.onCreate().
695 */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700696 /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700697 synchronized (PhoneInterfaceManager.class) {
698 if (sInstance == null) {
Sailesh Nepal194161e2014-07-03 08:57:44 -0700699 sInstance = new PhoneInterfaceManager(app, phone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700700 } else {
701 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
702 }
703 return sInstance;
704 }
705 }
706
707 /** Private constructor; @see init() */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700708 private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700709 mApp = app;
710 mPhone = phone;
711 mCM = PhoneGlobals.getInstance().mCM;
Derek Tan89e89d42014-07-08 17:00:10 -0700712 mSimplifiedNetworkSettings = new HashSet<Long>();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700713 mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
714 mMainThreadHandler = new MainThreadHandler();
Derek Tan7226c842014-07-02 17:42:23 -0700715 mAdnRecordsForDisplay = new HashMap<Long, AdnRecord>();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700716 publish();
717 }
718
719 private void publish() {
720 if (DBG) log("publish: " + this);
721
722 ServiceManager.addService("phone", this);
723 }
724
Wink Saville36469e72014-06-11 15:17:00 -0700725 // returns phone associated with the subId.
726 // getPhone(0) returns default phone in single SIM mode.
727 private Phone getPhone(long subId) {
728 // FIXME: hack for the moment
729 return mPhone;
730 // return PhoneUtils.getPhoneUsingSubId(subId);
731 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700732 //
733 // Implementation of the ITelephony interface.
734 //
735
736 public void dial(String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700737 dialUsingSubId(getPreferredVoiceSubscription(), number);
738 }
739
740 public void dialUsingSubId(long subId, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700741 if (DBG) log("dial: " + number);
742 // No permission check needed here: This is just a wrapper around the
743 // ACTION_DIAL intent, which is available to any app since it puts up
744 // the UI before it does anything.
745
746 String url = createTelUrl(number);
747 if (url == null) {
748 return;
749 }
750
751 // PENDING: should we just silently fail if phone is offhook or ringing?
Wink Saville36469e72014-06-11 15:17:00 -0700752 PhoneConstants.State state = mCM.getState(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700753 if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
754 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
755 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Wink Saville36469e72014-06-11 15:17:00 -0700756 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700757 mApp.startActivity(intent);
758 }
759 }
760
761 public void call(String callingPackage, String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700762 callUsingSubId(getPreferredVoiceSubscription(), callingPackage, number);
763 }
764
765 public void callUsingSubId(long subId, String callingPackage, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700766 if (DBG) log("call: " + number);
767
768 // This is just a wrapper around the ACTION_CALL intent, but we still
769 // need to do a permission check since we're calling startActivity()
770 // from the context of the phone app.
771 enforceCallPermission();
772
773 if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
774 != AppOpsManager.MODE_ALLOWED) {
775 return;
776 }
777
778 String url = createTelUrl(number);
779 if (url == null) {
780 return;
781 }
782
783 Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
Wink Saville36469e72014-06-11 15:17:00 -0700784 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700785 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
786 mApp.startActivity(intent);
787 }
788
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700789 /**
790 * End a call based on call state
791 * @return true is a call was ended
792 */
793 public boolean endCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700794 return endCallUsingSubId(getDefaultSubscription());
795 }
796
797 /**
798 * End a call based on the call state of the subId
799 * @return true is a call was ended
800 */
801 public boolean endCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700802 enforceCallPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700803 return (Boolean) sendRequest(CMD_END_CALL, subId, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700804 }
805
806 public void answerRingingCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700807 answerRingingCallUsingSubId(getDefaultSubscription());
808 }
809
810 public void answerRingingCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700811 if (DBG) log("answerRingingCall...");
812 // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
813 // but that can probably wait till the big TelephonyManager API overhaul.
814 // For now, protect this call with the MODIFY_PHONE_STATE permission.
815 enforceModifyPermission();
816 sendRequestAsync(CMD_ANSWER_RINGING_CALL);
817 }
818
819 /**
820 * Make the actual telephony calls to implement answerRingingCall().
821 * This should only be called from the main thread of the Phone app.
822 * @see #answerRingingCall
823 *
824 * TODO: it would be nice to return true if we answered the call, or
825 * false if there wasn't actually a ringing incoming call, or some
826 * other error occurred. (In other words, pass back the return value
827 * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
828 * But that would require calling this method via sendRequest() rather
829 * than sendRequestAsync(), and right now we don't actually *need* that
830 * return value, so let's just return void for now.
831 */
832 private void answerRingingCallInternal() {
833 final boolean hasRingingCall = !mPhone.getRingingCall().isIdle();
834 if (hasRingingCall) {
835 final boolean hasActiveCall = !mPhone.getForegroundCall().isIdle();
836 final boolean hasHoldingCall = !mPhone.getBackgroundCall().isIdle();
837 if (hasActiveCall && hasHoldingCall) {
838 // Both lines are in use!
839 // TODO: provide a flag to let the caller specify what
840 // policy to use if both lines are in use. (The current
841 // behavior is hardwired to "answer incoming, end ongoing",
842 // which is how the CALL button is specced to behave.)
843 PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
844 return;
845 } else {
846 // answerCall() will automatically hold the current active
847 // call, if there is one.
848 PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
849 return;
850 }
851 } else {
852 // No call was ringing.
853 return;
854 }
855 }
856
857 public void silenceRinger() {
858 if (DBG) log("silenceRinger...");
859 // TODO: find a more appropriate permission to check here.
860 // (That can probably wait till the big TelephonyManager API overhaul.
861 // For now, protect this call with the MODIFY_PHONE_STATE permission.)
862 enforceModifyPermission();
863 sendRequestAsync(CMD_SILENCE_RINGER);
864 }
865
866 /**
867 * Internal implemenation of silenceRinger().
868 * This should only be called from the main thread of the Phone app.
869 * @see #silenceRinger
870 */
871 private void silenceRingerInternal() {
872 if ((mCM.getState() == PhoneConstants.State.RINGING)
873 && mApp.notifier.isRinging()) {
874 // Ringer is actually playing, so silence it.
875 if (DBG) log("silenceRingerInternal: silencing...");
876 mApp.notifier.silenceRinger();
877 }
878 }
879
880 public boolean isOffhook() {
Wink Saville36469e72014-06-11 15:17:00 -0700881 return isOffhookUsingSubId(getDefaultSubscription());
882 }
883
884 public boolean isOffhookUsingSubId(long subId) {
885 return (getPhone(subId).getState() == PhoneConstants.State.OFFHOOK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700886 }
887
888 public boolean isRinging() {
Wink Saville36469e72014-06-11 15:17:00 -0700889 return (isRingingUsingSubId(getDefaultSubscription()));
890 }
891
892 public boolean isRingingUsingSubId(long subId) {
893 return (getPhone(subId).getState() == PhoneConstants.State.RINGING);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700894 }
895
896 public boolean isIdle() {
Wink Saville36469e72014-06-11 15:17:00 -0700897 return isIdleUsingSubId(getDefaultSubscription());
898 }
899
900 public boolean isIdleUsingSubId(long subId) {
901 return (getPhone(subId).getState() == PhoneConstants.State.IDLE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700902 }
903
904 public boolean isSimPinEnabled() {
905 enforceReadPermission();
906 return (PhoneGlobals.getInstance().isSimPinEnabled());
907 }
908
909 public boolean supplyPin(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700910 return supplyPinUsingSubId(getDefaultSubscription(), pin);
911 }
912
913 public boolean supplyPinUsingSubId(long subId, String pin) {
914 int [] resultArray = supplyPinReportResultUsingSubId(subId, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700915 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
916 }
917
918 public boolean supplyPuk(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700919 return supplyPukUsingSubId(getDefaultSubscription(), puk, pin);
920 }
921
922 public boolean supplyPukUsingSubId(long subId, String puk, String pin) {
923 int [] resultArray = supplyPukReportResultUsingSubId(subId, puk, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700924 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
925 }
926
927 /** {@hide} */
928 public int[] supplyPinReportResult(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700929 return supplyPinReportResultUsingSubId(getDefaultSubscription(), pin);
930 }
931
932 public int[] supplyPinReportResultUsingSubId(long subId, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700933 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700934 final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700935 checkSimPin.start();
936 return checkSimPin.unlockSim(null, pin);
937 }
938
Wink Saville9de0f752013-10-22 19:04:03 -0700939 /** {@hide} */
940 public int[] supplyPukReportResult(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700941 return supplyPukReportResultUsingSubId(getDefaultSubscription(), puk, pin);
942 }
943
944 public int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700945 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700946 final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700947 checkSimPuk.start();
948 return checkSimPuk.unlockSim(puk, pin);
949 }
950
951 /**
Wink Saville9de0f752013-10-22 19:04:03 -0700952 * Helper thread to turn async call to SimCard#supplyPin into
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700953 * a synchronous one.
954 */
955 private static class UnlockSim extends Thread {
956
957 private final IccCard mSimCard;
958
959 private boolean mDone = false;
Wink Saville9de0f752013-10-22 19:04:03 -0700960 private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
961 private int mRetryCount = -1;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700962
963 // For replies from SimCard interface
964 private Handler mHandler;
965
966 // For async handler to identify request type
967 private static final int SUPPLY_PIN_COMPLETE = 100;
968
969 public UnlockSim(IccCard simCard) {
970 mSimCard = simCard;
971 }
972
973 @Override
974 public void run() {
975 Looper.prepare();
976 synchronized (UnlockSim.this) {
977 mHandler = new Handler() {
978 @Override
979 public void handleMessage(Message msg) {
980 AsyncResult ar = (AsyncResult) msg.obj;
981 switch (msg.what) {
982 case SUPPLY_PIN_COMPLETE:
983 Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
984 synchronized (UnlockSim.this) {
Wink Saville9de0f752013-10-22 19:04:03 -0700985 mRetryCount = msg.arg1;
986 if (ar.exception != null) {
987 if (ar.exception instanceof CommandException &&
988 ((CommandException)(ar.exception)).getCommandError()
989 == CommandException.Error.PASSWORD_INCORRECT) {
990 mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
991 } else {
992 mResult = PhoneConstants.PIN_GENERAL_FAILURE;
993 }
994 } else {
995 mResult = PhoneConstants.PIN_RESULT_SUCCESS;
996 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700997 mDone = true;
998 UnlockSim.this.notifyAll();
999 }
1000 break;
1001 }
1002 }
1003 };
1004 UnlockSim.this.notifyAll();
1005 }
1006 Looper.loop();
1007 }
1008
1009 /*
1010 * Use PIN or PUK to unlock SIM card
1011 *
1012 * If PUK is null, unlock SIM card with PIN
1013 *
1014 * If PUK is not null, unlock SIM card with PUK and set PIN code
1015 */
Wink Saville9de0f752013-10-22 19:04:03 -07001016 synchronized int[] unlockSim(String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001017
1018 while (mHandler == null) {
1019 try {
1020 wait();
1021 } catch (InterruptedException e) {
1022 Thread.currentThread().interrupt();
1023 }
1024 }
1025 Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
1026
1027 if (puk == null) {
1028 mSimCard.supplyPin(pin, callback);
1029 } else {
1030 mSimCard.supplyPuk(puk, pin, callback);
1031 }
1032
1033 while (!mDone) {
1034 try {
1035 Log.d(LOG_TAG, "wait for done");
1036 wait();
1037 } catch (InterruptedException e) {
1038 // Restore the interrupted status
1039 Thread.currentThread().interrupt();
1040 }
1041 }
1042 Log.d(LOG_TAG, "done");
Wink Saville9de0f752013-10-22 19:04:03 -07001043 int[] resultArray = new int[2];
1044 resultArray[0] = mResult;
1045 resultArray[1] = mRetryCount;
1046 return resultArray;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001047 }
1048 }
1049
1050 public void updateServiceLocation() {
Wink Saville36469e72014-06-11 15:17:00 -07001051 updateServiceLocationUsingSubId(getDefaultSubscription());
1052
1053 }
1054
1055 public void updateServiceLocationUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001056 // No permission check needed here: this call is harmless, and it's
1057 // needed for the ServiceState.requestStateUpdate() call (which is
1058 // already intentionally exposed to 3rd parties.)
Wink Saville36469e72014-06-11 15:17:00 -07001059 getPhone(subId).updateServiceLocation();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001060 }
1061
1062 public boolean isRadioOn() {
Wink Saville36469e72014-06-11 15:17:00 -07001063 return isRadioOnUsingSubId(getDefaultSubscription());
1064 }
1065
1066 public boolean isRadioOnUsingSubId(long subId) {
1067 return getPhone(subId).getServiceState().getState() != ServiceState.STATE_POWER_OFF;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001068 }
1069
1070 public void toggleRadioOnOff() {
Wink Saville36469e72014-06-11 15:17:00 -07001071 toggleRadioOnOffUsingSubId(getDefaultSubscription());
1072
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001073 }
Wink Saville36469e72014-06-11 15:17:00 -07001074
1075 public void toggleRadioOnOffUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001076 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001077 getPhone(subId).setRadioPower(!isRadioOnUsingSubId(subId));
1078 }
1079
1080 public boolean setRadio(boolean turnOn) {
1081 return setRadioUsingSubId(getDefaultSubscription(), turnOn);
1082 }
1083
1084 public boolean setRadioUsingSubId(long subId, boolean turnOn) {
1085 enforceModifyPermission();
1086 if ((getPhone(subId).getServiceState().getState() !=
1087 ServiceState.STATE_POWER_OFF) != turnOn) {
1088 toggleRadioOnOffUsingSubId(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001089 }
1090 return true;
1091 }
Wink Saville36469e72014-06-11 15:17:00 -07001092
Naveen Kalla1fd79bd2014-08-08 00:48:59 -07001093 public boolean needMobileRadioShutdown() {
1094 /*
1095 * If any of the Radios are available, it will need to be
1096 * shutdown. So return true if any Radio is available.
1097 */
1098 for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
1099 Phone phone = PhoneFactory.getPhone(i);
1100 if (phone != null && phone.isRadioAvailable()) return true;
1101 }
1102 logv(TelephonyManager.getDefault().getPhoneCount() + " Phones are shutdown.");
1103 return false;
1104 }
1105
1106 public void shutdownMobileRadios() {
1107 for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
1108 logv("Shutting down Phone " + i);
1109 shutdownRadioUsingPhoneId(i);
1110 }
1111 }
1112
1113 private void shutdownRadioUsingPhoneId(int phoneId) {
1114 enforceModifyPermission();
1115 Phone phone = PhoneFactory.getPhone(phoneId);
1116 if (phone != null && phone.isRadioAvailable()) {
1117 phone.shutdownRadio();
1118 }
1119 }
1120
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001121 public boolean setRadioPower(boolean turnOn) {
Wink Saville36469e72014-06-11 15:17:00 -07001122 return setRadioPowerUsingSubId(getDefaultSubscription(), turnOn);
1123 }
1124
1125 public boolean setRadioPowerUsingSubId(long subId, boolean turnOn) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001126 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001127 getPhone(subId).setRadioPower(turnOn);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001128 return true;
1129 }
1130
Wink Saville36469e72014-06-11 15:17:00 -07001131 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001132 public boolean enableDataConnectivity() {
1133 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001134 long subId = SubscriptionManager.getDefaultDataSubId();
1135 getPhone(subId).setDataEnabled(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001136 return true;
1137 }
1138
Wink Saville36469e72014-06-11 15:17:00 -07001139 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001140 public boolean disableDataConnectivity() {
1141 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001142 long subId = SubscriptionManager.getDefaultDataSubId();
1143 getPhone(subId).setDataEnabled(false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001144 return true;
1145 }
1146
Wink Saville36469e72014-06-11 15:17:00 -07001147 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001148 public boolean isDataConnectivityPossible() {
Wink Saville36469e72014-06-11 15:17:00 -07001149 long subId = SubscriptionManager.getDefaultDataSubId();
1150 return getPhone(subId).isDataConnectivityPossible();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001151 }
1152
1153 public boolean handlePinMmi(String dialString) {
Wink Saville36469e72014-06-11 15:17:00 -07001154 return handlePinMmiUsingSubId(getDefaultSubscription(), dialString);
1155 }
1156
1157 public boolean handlePinMmiUsingSubId(long subId, String dialString) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001158 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001159 return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001160 }
1161
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001162 public int getCallState() {
Wink Saville36469e72014-06-11 15:17:00 -07001163 return getCallStateUsingSubId(getDefaultSubscription());
1164 }
1165
1166 public int getCallStateUsingSubId(long subId) {
1167 return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001168 }
1169
1170 public int getDataState() {
Wink Saville36469e72014-06-11 15:17:00 -07001171 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1172 return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001173 }
1174
1175 public int getDataActivity() {
Wink Saville36469e72014-06-11 15:17:00 -07001176 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1177 return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001178 }
1179
1180 @Override
1181 public Bundle getCellLocation() {
1182 try {
1183 mApp.enforceCallingOrSelfPermission(
1184 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1185 } catch (SecurityException e) {
1186 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1187 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1188 // is the weaker precondition
1189 mApp.enforceCallingOrSelfPermission(
1190 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1191 }
1192
Jake Hambye994d462014-02-03 13:10:13 -08001193 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001194 if (DBG_LOC) log("getCellLocation: is active user");
1195 Bundle data = new Bundle();
1196 mPhone.getCellLocation().fillInNotifierBundle(data);
1197 return data;
1198 } else {
1199 if (DBG_LOC) log("getCellLocation: suppress non-active user");
1200 return null;
1201 }
1202 }
1203
1204 @Override
1205 public void enableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001206 enableLocationUpdatesUsingSubId(getDefaultSubscription());
1207 }
1208
1209 public void enableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001210 mApp.enforceCallingOrSelfPermission(
1211 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001212 getPhone(subId).enableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001213 }
1214
1215 @Override
1216 public void disableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001217 disableLocationUpdatesUsingSubId(getDefaultSubscription());
1218 }
1219
1220 public void disableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001221 mApp.enforceCallingOrSelfPermission(
1222 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001223 getPhone(subId).disableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001224 }
1225
1226 @Override
1227 @SuppressWarnings("unchecked")
1228 public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1229 try {
1230 mApp.enforceCallingOrSelfPermission(
1231 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1232 } catch (SecurityException e) {
1233 // If we have ACCESS_FINE_LOCATION permission, skip the check
1234 // for ACCESS_COARSE_LOCATION
1235 // A failure should throw the SecurityException from
1236 // ACCESS_COARSE_LOCATION since this is the weaker precondition
1237 mApp.enforceCallingOrSelfPermission(
1238 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1239 }
1240
1241 if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1242 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1243 return null;
1244 }
Jake Hambye994d462014-02-03 13:10:13 -08001245 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001246 if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1247
1248 ArrayList<NeighboringCellInfo> cells = null;
1249
1250 try {
1251 cells = (ArrayList<NeighboringCellInfo>) sendRequest(
Wink Saville36469e72014-06-11 15:17:00 -07001252 CMD_HANDLE_NEIGHBORING_CELL, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001253 } catch (RuntimeException e) {
Wink Saville36469e72014-06-11 15:17:00 -07001254 Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001255 }
1256 return cells;
1257 } else {
1258 if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1259 return null;
1260 }
1261 }
1262
1263
1264 @Override
1265 public List<CellInfo> getAllCellInfo() {
1266 try {
1267 mApp.enforceCallingOrSelfPermission(
1268 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1269 } catch (SecurityException e) {
1270 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1271 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1272 // is the weaker precondition
1273 mApp.enforceCallingOrSelfPermission(
1274 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1275 }
1276
Jake Hambye994d462014-02-03 13:10:13 -08001277 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001278 if (DBG_LOC) log("getAllCellInfo: is active user");
1279 return mPhone.getAllCellInfo();
1280 } else {
1281 if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1282 return null;
1283 }
1284 }
1285
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -07001286 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001287 public void setCellInfoListRate(int rateInMillis) {
1288 mPhone.setCellInfoListRate(rateInMillis);
1289 }
1290
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001291 //
1292 // Internal helper methods.
1293 //
1294
Jake Hambye994d462014-02-03 13:10:13 -08001295 private static boolean checkIfCallerIsSelfOrForegroundUser() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001296 boolean ok;
1297
1298 boolean self = Binder.getCallingUid() == Process.myUid();
1299 if (!self) {
1300 // Get the caller's user id then clear the calling identity
1301 // which will be restored in the finally clause.
1302 int callingUser = UserHandle.getCallingUserId();
1303 long ident = Binder.clearCallingIdentity();
1304
1305 try {
1306 // With calling identity cleared the current user is the foreground user.
1307 int foregroundUser = ActivityManager.getCurrentUser();
1308 ok = (foregroundUser == callingUser);
1309 if (DBG_LOC) {
1310 log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1311 + " callingUser=" + callingUser + " ok=" + ok);
1312 }
1313 } catch (Exception ex) {
1314 if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1315 ok = false;
1316 } finally {
1317 Binder.restoreCallingIdentity(ident);
1318 }
1319 } else {
1320 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1321 ok = true;
1322 }
1323 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1324 return ok;
1325 }
1326
1327 /**
1328 * Make sure the caller has the READ_PHONE_STATE permission.
1329 *
1330 * @throws SecurityException if the caller does not have the required permission
1331 */
1332 private void enforceReadPermission() {
1333 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
1334 }
1335
1336 /**
1337 * Make sure the caller has the MODIFY_PHONE_STATE permission.
1338 *
1339 * @throws SecurityException if the caller does not have the required permission
1340 */
1341 private void enforceModifyPermission() {
1342 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1343 }
1344
1345 /**
Junda Liua2e36012014-07-09 18:30:01 -07001346 * Make sure either system app or the caller has carrier privilege.
1347 *
1348 * @throws SecurityException if the caller does not have the required permission/privilege
1349 */
1350 private void enforceModifyPermissionOrCarrierPrivilege() {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001351 int permission = mApp.checkCallingOrSelfPermission(
1352 android.Manifest.permission.MODIFY_PHONE_STATE);
1353 if (permission == PackageManager.PERMISSION_GRANTED) {
1354 return;
1355 }
1356
1357 log("No modify permission, check carrier privilege next.");
1358 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1359 loge("No Carrier Privilege.");
1360 throw new SecurityException("No modify permission or carrier privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001361 }
1362 }
1363
1364 /**
1365 * Make sure the caller has carrier privilege.
1366 *
1367 * @throws SecurityException if the caller does not have the required permission
1368 */
1369 private void enforceCarrierPrivilege() {
1370 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001371 loge("No Carrier Privilege.");
1372 throw new SecurityException("No Carrier Privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001373 }
1374 }
1375
1376 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001377 * Make sure the caller has the CALL_PHONE permission.
1378 *
1379 * @throws SecurityException if the caller does not have the required permission
1380 */
1381 private void enforceCallPermission() {
1382 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1383 }
1384
Shishir Agrawal566b7612013-10-28 14:41:00 -07001385 /**
Gabriel Peal36ebb0d2014-03-20 09:20:43 -07001386 * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1387 *
1388 * @throws SecurityException if the caller does not have the required permission
1389 */
1390 private void enforcePrivilegedPhoneStatePermission() {
1391 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1392 null);
1393 }
1394
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001395 private String createTelUrl(String number) {
1396 if (TextUtils.isEmpty(number)) {
1397 return null;
1398 }
1399
Jake Hambye994d462014-02-03 13:10:13 -08001400 return "tel:" + number;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001401 }
1402
Ihab Awadf9e92732013-12-05 18:02:52 -08001403 private static void log(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001404 Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1405 }
1406
Naveen Kalla1fd79bd2014-08-08 00:48:59 -07001407 private static void logv(String msg) {
1408 Log.v(LOG_TAG, "[PhoneIntfMgr] " + msg);
1409 }
1410
Ihab Awadf9e92732013-12-05 18:02:52 -08001411 private static void loge(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001412 Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1413 }
1414
1415 public int getActivePhoneType() {
Wink Saville36469e72014-06-11 15:17:00 -07001416 return getActivePhoneTypeUsingSubId(getDefaultSubscription());
1417 }
1418
1419 public int getActivePhoneTypeUsingSubId(long subId) {
1420 return getPhone(subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001421 }
1422
1423 /**
1424 * Returns the CDMA ERI icon index to display
1425 */
1426 public int getCdmaEriIconIndex() {
Wink Saville36469e72014-06-11 15:17:00 -07001427 return getCdmaEriIconIndexUsingSubId(getDefaultSubscription());
1428
1429 }
1430
1431 public int getCdmaEriIconIndexUsingSubId(long subId) {
1432 return getPhone(subId).getCdmaEriIconIndex();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001433 }
1434
1435 /**
1436 * Returns the CDMA ERI icon mode,
1437 * 0 - ON
1438 * 1 - FLASHING
1439 */
1440 public int getCdmaEriIconMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001441 return getCdmaEriIconModeUsingSubId(getDefaultSubscription());
1442 }
1443
1444 public int getCdmaEriIconModeUsingSubId(long subId) {
1445 return getPhone(subId).getCdmaEriIconMode();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001446 }
1447
1448 /**
1449 * Returns the CDMA ERI text,
1450 */
1451 public String getCdmaEriText() {
Wink Saville36469e72014-06-11 15:17:00 -07001452 return getCdmaEriTextUsingSubId(getDefaultSubscription());
1453 }
1454
1455 public String getCdmaEriTextUsingSubId(long subId) {
1456 return getPhone(subId).getCdmaEriText();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001457 }
1458
1459 /**
Junda Liuca05d5d2014-08-14 22:36:34 -07001460 * Returns the CDMA MDN.
1461 */
1462 public String getCdmaMdn(long subId) {
1463 enforceModifyPermissionOrCarrierPrivilege();
1464 if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
1465 return getPhone(subId).getLine1Number();
1466 } else {
1467 return null;
1468 }
1469 }
1470
1471 /**
1472 * Returns the CDMA MIN.
1473 */
1474 public String getCdmaMin(long subId) {
1475 enforceModifyPermissionOrCarrierPrivilege();
1476 if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
1477 return getPhone(subId).getCdmaMin();
1478 } else {
1479 return null;
1480 }
1481 }
1482
1483 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001484 * Returns true if CDMA provisioning needs to run.
1485 */
1486 public boolean needsOtaServiceProvisioning() {
1487 return mPhone.needsOtaServiceProvisioning();
1488 }
1489
1490 /**
1491 * Returns the unread count of voicemails
1492 */
1493 public int getVoiceMessageCount() {
Wink Saville36469e72014-06-11 15:17:00 -07001494 return getVoiceMessageCountUsingSubId(getDefaultSubscription());
1495 }
1496
1497 /**
1498 * Returns the unread count of voicemails for a subId
1499 */
1500 public int getVoiceMessageCountUsingSubId( long subId) {
1501 return getPhone(subId).getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001502 }
1503
1504 /**
1505 * Returns the data network type
1506 *
1507 * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1508 */
1509 @Override
1510 public int getNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001511 return getNetworkTypeUsingSubId(getDefaultSubscription());
1512 }
1513
1514 /**
1515 * Returns the network type for a subId
1516 */
1517 @Override
1518 public int getNetworkTypeUsingSubId(long subId) {
1519 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001520 }
1521
1522 /**
1523 * Returns the data network type
1524 */
1525 @Override
1526 public int getDataNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001527 return getDataNetworkTypeUsingSubId(getDefaultSubscription());
1528 }
1529
1530 /**
1531 * Returns the data network type for a subId
1532 */
1533 @Override
1534 public int getDataNetworkTypeUsingSubId(long subId) {
1535 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001536 }
1537
1538 /**
1539 * Returns the data network type
1540 */
1541 @Override
1542 public int getVoiceNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001543 return getVoiceNetworkTypeUsingSubId(getDefaultSubscription());
1544 }
1545
1546 /**
1547 * Returns the Voice network type for a subId
1548 */
1549 @Override
1550 public int getVoiceNetworkTypeUsingSubId(long subId) {
1551 return getPhone(subId).getServiceState().getVoiceNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001552 }
1553
1554 /**
1555 * @return true if a ICC card is present
1556 */
1557 public boolean hasIccCard() {
Wink Saville36469e72014-06-11 15:17:00 -07001558 // FIXME Make changes to pass defaultSimId of type int
1559 return hasIccCardUsingSlotId(getDefaultSubscription());
1560 }
1561
1562 /**
1563 * @return true if a ICC card is present for a slotId
1564 */
1565 public boolean hasIccCardUsingSlotId(long slotId) {
1566 return getPhone(slotId).getIccCard().hasIccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001567 }
1568
1569 /**
1570 * Return if the current radio is LTE on CDMA. This
1571 * is a tri-state return value as for a period of time
1572 * the mode may be unknown.
1573 *
1574 * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
Jake Hambye994d462014-02-03 13:10:13 -08001575 * or {@link Phone#LTE_ON_CDMA_TRUE}
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001576 */
1577 public int getLteOnCdmaMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001578 return getLteOnCdmaModeUsingSubId(getDefaultSubscription());
1579 }
1580
1581 public int getLteOnCdmaModeUsingSubId(long subId) {
1582 return getPhone(subId).getLteOnCdmaMode();
1583 }
1584
1585 public void setPhone(Phone phone) {
1586 mPhone = phone;
1587 }
1588
1589 /**
1590 * {@hide}
1591 * Returns Default subId, 0 in the case of single standby.
1592 */
1593 private long getDefaultSubscription() {
1594 return SubscriptionManager.getDefaultSubId();
1595 }
1596
1597 private long getPreferredVoiceSubscription() {
1598 return SubscriptionManager.getDefaultVoiceSubId();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001599 }
Ihab Awadf2177b72013-11-25 13:33:23 -08001600
1601 /**
1602 * @see android.telephony.TelephonyManager.WifiCallingChoices
1603 */
1604 public int getWhenToMakeWifiCalls() {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001605 return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1606 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
Ihab Awadf2177b72013-11-25 13:33:23 -08001607 }
1608
1609 /**
1610 * @see android.telephony.TelephonyManager.WifiCallingChoices
1611 */
1612 public void setWhenToMakeWifiCalls(int preference) {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001613 if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1614 Settings.System.putInt(mPhone.getContext().getContentResolver(),
1615 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
Ihab Awadf9e92732013-12-05 18:02:52 -08001616 }
1617
Sailesh Nepald1e68152013-12-12 19:08:02 -08001618 private static int getWhenToMakeWifiCallsDefaultPreference() {
Santos Cordonda120f42014-08-06 04:44:34 -07001619 // TODO: Use a build property to choose this value.
Evan Charlton9829e882013-12-19 15:30:38 -08001620 return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
Ihab Awadf2177b72013-11-25 13:33:23 -08001621 }
Shishir Agrawal69f68122013-12-16 17:25:49 -08001622
Shishir Agrawal566b7612013-10-28 14:41:00 -07001623 @Override
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001624 public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID) {
Junda Liua2e36012014-07-09 18:30:01 -07001625 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001626
1627 if (DBG) log("iccOpenLogicalChannel: " + AID);
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001628 IccOpenLogicalChannelResponse response = (IccOpenLogicalChannelResponse)sendRequest(
1629 CMD_OPEN_CHANNEL, AID);
1630 if (DBG) log("iccOpenLogicalChannel: " + response);
1631 return response;
Shishir Agrawal566b7612013-10-28 14:41:00 -07001632 }
1633
1634 @Override
1635 public boolean iccCloseLogicalChannel(int channel) {
Junda Liua2e36012014-07-09 18:30:01 -07001636 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001637
1638 if (DBG) log("iccCloseLogicalChannel: " + channel);
1639 if (channel < 0) {
1640 return false;
1641 }
Jake Hambye994d462014-02-03 13:10:13 -08001642 Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
Shishir Agrawal566b7612013-10-28 14:41:00 -07001643 if (DBG) log("iccCloseLogicalChannel: " + success);
1644 return success;
1645 }
1646
1647 @Override
1648 public String iccTransmitApduLogicalChannel(int channel, int cla,
1649 int command, int p1, int p2, int p3, String data) {
Junda Liua2e36012014-07-09 18:30:01 -07001650 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001651
1652 if (DBG) {
1653 log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1654 " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1655 " data=" + data);
1656 }
1657
1658 if (channel < 0) {
1659 return "";
1660 }
1661
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001662 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_LOGICAL_CHANNEL,
Shishir Agrawal566b7612013-10-28 14:41:00 -07001663 new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1664 if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1665
Shishir Agrawal566b7612013-10-28 14:41:00 -07001666 // Append the returned status code to the end of the response payload.
1667 String s = Integer.toHexString(
1668 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
Shishir Agrawal5ec14172014-08-05 17:05:45 -07001669 if (response.payload != null) {
1670 s = IccUtils.bytesToHexString(response.payload) + s;
1671 }
Shishir Agrawal566b7612013-10-28 14:41:00 -07001672 return s;
1673 }
Jake Hambye994d462014-02-03 13:10:13 -08001674
Evan Charltonc66da362014-05-16 14:06:40 -07001675 @Override
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001676 public String iccTransmitApduBasicChannel(int cla, int command, int p1, int p2,
1677 int p3, String data) {
1678 enforceModifyPermissionOrCarrierPrivilege();
1679
1680 if (DBG) {
1681 log("iccTransmitApduBasicChannel: cla=" + cla + " cmd=" + command + " p1="
1682 + p1 + " p2=" + p2 + " p3=" + p3 + " data=" + data);
1683 }
1684
1685 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_BASIC_CHANNEL,
1686 new IccAPDUArgument(0, cla, command, p1, p2, p3, data));
1687 if (DBG) log("iccTransmitApduBasicChannel: " + response);
1688
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001689 // Append the returned status code to the end of the response payload.
1690 String s = Integer.toHexString(
1691 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
Shishir Agrawal5ec14172014-08-05 17:05:45 -07001692 if (response.payload != null) {
1693 s = IccUtils.bytesToHexString(response.payload) + s;
1694 }
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001695 return s;
1696 }
1697
1698 @Override
1699 public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
1700 String filePath) {
1701 enforceModifyPermissionOrCarrierPrivilege();
1702
1703 if (DBG) {
1704 log("Exchange SIM_IO " + fileID + ":" + command + " " +
1705 p1 + " " + p2 + " " + p3 + ":" + filePath);
1706 }
1707
1708 IccIoResult response =
1709 (IccIoResult)sendRequest(CMD_EXCHANGE_SIM_IO,
1710 new IccAPDUArgument(fileID, command, -1, p1, p2, p3, filePath));
1711
1712 if (DBG) {
1713 log("Exchange SIM_IO [R]" + response);
1714 }
1715
1716 byte[] result = null;
1717 int length = 2;
1718 if (response.payload != null) {
1719 length = 2 + response.payload.length;
1720 result = new byte[length];
1721 System.arraycopy(response.payload, 0, result, 0, response.payload.length);
1722 } else {
1723 result = new byte[length];
1724 }
1725
1726 result[length - 1] = (byte) response.sw2;
1727 result[length - 2] = (byte) response.sw1;
1728 return result;
1729 }
1730
1731 @Override
Evan Charltonc66da362014-05-16 14:06:40 -07001732 public String sendEnvelopeWithStatus(String content) {
Junda Liua2e36012014-07-09 18:30:01 -07001733 enforceModifyPermissionOrCarrierPrivilege();
Evan Charltonc66da362014-05-16 14:06:40 -07001734
1735 IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
1736 if (response.payload == null) {
1737 return "";
1738 }
1739
1740 // Append the returned status code to the end of the response payload.
1741 String s = Integer.toHexString(
1742 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1743 s = IccUtils.bytesToHexString(response.payload) + s;
1744 return s;
1745 }
1746
Jake Hambye994d462014-02-03 13:10:13 -08001747 /**
1748 * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1749 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1750 *
1751 * @param itemID the ID of the item to read
1752 * @return the NV item as a String, or null on error.
1753 */
1754 @Override
1755 public String nvReadItem(int itemID) {
Junda Liua2e36012014-07-09 18:30:01 -07001756 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001757 if (DBG) log("nvReadItem: item " + itemID);
1758 String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
1759 if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
1760 return value;
1761 }
1762
1763 /**
1764 * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1765 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1766 *
1767 * @param itemID the ID of the item to read
1768 * @param itemValue the value to write, as a String
1769 * @return true on success; false on any failure
1770 */
1771 @Override
1772 public boolean nvWriteItem(int itemID, String itemValue) {
Junda Liua2e36012014-07-09 18:30:01 -07001773 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001774 if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
1775 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
1776 new Pair<Integer, String>(itemID, itemValue));
1777 if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
1778 return success;
1779 }
1780
1781 /**
1782 * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
1783 * Used for device configuration by some CDMA operators.
1784 *
1785 * @param preferredRoamingList byte array containing the new PRL
1786 * @return true on success; false on any failure
1787 */
1788 @Override
1789 public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
Junda Liua2e36012014-07-09 18:30:01 -07001790 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001791 if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
1792 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
1793 if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
1794 return success;
1795 }
1796
1797 /**
1798 * Perform the specified type of NV config reset.
1799 * Used for device configuration by some CDMA operators.
1800 *
1801 * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
1802 * @return true on success; false on any failure
1803 */
1804 @Override
1805 public boolean nvResetConfig(int resetType) {
Junda Liua2e36012014-07-09 18:30:01 -07001806 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001807 if (DBG) log("nvResetConfig: type " + resetType);
1808 Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
1809 if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
1810 return success;
1811 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001812
1813 /**
Wink Saville36469e72014-06-11 15:17:00 -07001814 * {@hide}
1815 * Returns Default sim, 0 in the case of single standby.
1816 */
1817 public int getDefaultSim() {
1818 //TODO Need to get it from Telephony Devcontroller
1819 return 0;
1820 }
1821
ram87fca6f2014-07-18 18:58:44 +05301822 public String[] getPcscfAddress(String apnType) {
Wink Saville36469e72014-06-11 15:17:00 -07001823 enforceReadPermission();
ram87fca6f2014-07-18 18:58:44 +05301824 return mPhone.getPcscfAddress(apnType);
Wink Saville36469e72014-06-11 15:17:00 -07001825 }
1826
1827 public void setImsRegistrationState(boolean registered) {
1828 enforceModifyPermission();
1829 mPhone.setImsRegistrationState(registered);
1830 }
1831
1832 /**
Junda Liu84d15a22014-07-02 11:21:04 -07001833 * Get the calculated preferred network type.
1834 * Used for debugging incorrect network type.
1835 *
1836 * @return the preferred network type, defined in RILConstants.java.
1837 */
1838 @Override
1839 public int getCalculatedPreferredNetworkType() {
1840 enforceReadPermission();
1841 return PhoneFactory.calculatePreferredNetworkType(mPhone.getContext());
1842 }
1843
1844 /**
Jake Hamby7c27be32014-03-03 13:25:59 -08001845 * Get the preferred network type.
1846 * Used for device configuration by some CDMA operators.
1847 *
1848 * @return the preferred network type, defined in RILConstants.java.
1849 */
1850 @Override
1851 public int getPreferredNetworkType() {
Junda Liua2e36012014-07-09 18:30:01 -07001852 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001853 if (DBG) log("getPreferredNetworkType");
1854 int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null);
1855 int networkType = (result != null ? result[0] : -1);
1856 if (DBG) log("getPreferredNetworkType: " + networkType);
1857 return networkType;
1858 }
1859
1860 /**
1861 * Set the preferred network type.
1862 * Used for device configuration by some CDMA operators.
1863 *
1864 * @param networkType the preferred network type, defined in RILConstants.java.
1865 * @return true on success; false on any failure.
1866 */
1867 @Override
1868 public boolean setPreferredNetworkType(int networkType) {
Junda Liua2e36012014-07-09 18:30:01 -07001869 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001870 if (DBG) log("setPreferredNetworkType: type " + networkType);
1871 Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType);
1872 if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
Junda Liu80bc0d12014-07-14 16:36:44 -07001873 if (success) {
1874 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1875 Settings.Global.PREFERRED_NETWORK_MODE, networkType);
1876 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001877 return success;
1878 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001879
1880 /**
Junda Liu787bc7e2014-06-30 13:38:02 -07001881 * Set the CDMA subscription source.
1882 * Used for device supporting both NV and RUIM for CDMA.
1883 *
1884 * @param subscriptionType the subscription type, 0 for RUIM, 1 for NV.
1885 * @return true on success; false on any failure.
1886 */
1887 @Override
1888 public boolean setCdmaSubscription(int subscriptionType) {
Junda Liua2e36012014-07-09 18:30:01 -07001889 enforceModifyPermissionOrCarrierPrivilege();
Junda Liu787bc7e2014-06-30 13:38:02 -07001890 if (DBG) log("setCdmaSubscription: type " + subscriptionType);
1891 if (subscriptionType != mPhone.CDMA_SUBSCRIPTION_RUIM_SIM &&
1892 subscriptionType != mPhone.CDMA_SUBSCRIPTION_NV) {
1893 loge("setCdmaSubscription: unsupported subscriptionType.");
1894 return false;
1895 }
1896 Boolean success = (Boolean) sendRequest(CMD_SET_CDMA_SUBSCRIPTION, subscriptionType);
1897 if (DBG) log("setCdmaSubscription: " + (success ? "ok" : "fail"));
1898 if (success) {
1899 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1900 Settings.Global.CDMA_SUBSCRIPTION_MODE, subscriptionType);
1901 }
1902 return success;
1903 }
1904
1905 /**
Robert Greenwalted86e582014-05-21 20:03:20 -07001906 * Set mobile data enabled
1907 * Used by the user through settings etc to turn on/off mobile data
1908 *
1909 * @param enable {@code true} turn turn data on, else {@code false}
1910 */
1911 @Override
1912 public void setDataEnabled(boolean enable) {
1913 enforceModifyPermission();
1914 mPhone.setDataEnabled(enable);
1915 }
1916
1917 /**
Robert Greenwalt646120a2014-05-23 11:54:03 -07001918 * Get whether mobile data is enabled.
1919 *
1920 * Note that this used to be available from ConnectivityService, gated by
1921 * ACCESS_NETWORK_STATE permission, so this will accept either that or
1922 * our MODIFY_PHONE_STATE.
Robert Greenwalted86e582014-05-21 20:03:20 -07001923 *
1924 * @return {@code true} if data is enabled else {@code false}
1925 */
1926 @Override
1927 public boolean getDataEnabled() {
Robert Greenwalt646120a2014-05-23 11:54:03 -07001928 try {
1929 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
1930 null);
1931 } catch (Exception e) {
1932 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
1933 null);
1934 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001935 return mPhone.getDataEnabled();
1936 }
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001937
1938 @Override
1939 public int hasCarrierPrivileges() {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001940 UiccCard card = UiccController.getInstance().getUiccCard();
1941 if (card == null) {
1942 loge("hasCarrierPrivileges: No UICC");
1943 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1944 }
1945 return card.getCarrierPrivilegeStatusForCurrentTransaction(
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001946 mPhone.getContext().getPackageManager());
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001947 }
Junda Liu29340342014-07-10 15:23:27 -07001948
1949 @Override
Shishir Agrawal6d5a2852014-07-11 16:32:57 -07001950 public int checkCarrierPrivilegesForPackage(String pkgname) {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001951 UiccCard card = UiccController.getInstance().getUiccCard();
1952 if (card == null) {
1953 loge("checkCarrierPrivilegesForPackage: No UICC");
1954 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1955 }
1956 return card.getCarrierPrivilegeStatus(mPhone.getContext().getPackageManager(), pkgname);
Junda Liu29340342014-07-10 15:23:27 -07001957 }
Derek Tan89e89d42014-07-08 17:00:10 -07001958
1959 @Override
Diego Pontorieroaf74c862014-08-28 11:51:16 -07001960 public List<String> getCarrierPackageNamesForIntent(Intent intent) {
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001961 UiccCard card = UiccController.getInstance().getUiccCard();
1962 if (card == null) {
Diego Pontorieroaf74c862014-08-28 11:51:16 -07001963 loge("getCarrierPackageNamesForIntent: No UICC");
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001964 return null ;
1965 }
Diego Pontorieroaf74c862014-08-28 11:51:16 -07001966 return card.getCarrierPackageNamesForIntent(
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001967 mPhone.getContext().getPackageManager(), intent);
1968 }
1969
1970 @Override
Derek Tan89e89d42014-07-08 17:00:10 -07001971 public void enableSimplifiedNetworkSettings(long subId, boolean enable) {
Derek Tan352d8cd2014-07-12 12:57:11 -07001972 enforceModifyPermissionOrCarrierPrivilege();
Derek Tan89e89d42014-07-08 17:00:10 -07001973 if (enable) {
1974 mSimplifiedNetworkSettings.add(subId);
1975 } else {
1976 mSimplifiedNetworkSettings.remove(subId);
1977 }
1978 }
1979
1980 @Override
1981 public boolean getSimplifiedNetworkSettingsEnabled(long subId) {
1982 enforceReadPermission();
1983 return mSimplifiedNetworkSettings.contains(subId);
1984 }
Derek Tan7226c842014-07-02 17:42:23 -07001985
1986 @Override
1987 public void setLine1NumberForDisplay(long subId, String alphaTag, String number) {
Derek Tan352d8cd2014-07-12 12:57:11 -07001988 enforceModifyPermissionOrCarrierPrivilege();
Derek Tan7226c842014-07-02 17:42:23 -07001989 mAdnRecordsForDisplay.put(subId, new AdnRecord(alphaTag, number));
1990 }
1991
1992 @Override
1993 public String getLine1NumberForDisplay(long subId) {
1994 enforceReadPermission();
1995 if (!mAdnRecordsForDisplay.containsKey(subId)) {
1996 return null;
1997 }
1998 AdnRecord adnRecord = mAdnRecordsForDisplay.get(subId);
1999 if (adnRecord.getNumber() == null || adnRecord.getNumber().isEmpty()) {
2000 return null;
2001 }
2002 return adnRecord.getNumber();
2003 }
2004
2005 @Override
2006 public String getLine1AlphaTagForDisplay(long subId) {
2007 enforceReadPermission();
2008 if (!mAdnRecordsForDisplay.containsKey(subId)) {
2009 return null;
2010 }
2011 AdnRecord adnRecord = mAdnRecordsForDisplay.get(subId);
2012 if (adnRecord.getAlphaTag() == null || adnRecord.getAlphaTag().isEmpty()) {
2013 return null;
2014 }
2015 return adnRecord.getAlphaTag();
2016 }
Shishir Agrawalb1ebf8c2014-07-17 16:32:41 -07002017
2018 @Override
Shishir Agrawala3dfd752014-09-04 13:25:42 -07002019 public boolean setOperatorBrandOverride(String brand) {
Shishir Agrawalb1ebf8c2014-07-17 16:32:41 -07002020 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawala3dfd752014-09-04 13:25:42 -07002021 return mPhone.setOperatorBrandOverride(brand);
Shishir Agrawalb1ebf8c2014-07-17 16:32:41 -07002022 }
Steven Liu4bf01bc2014-07-17 11:05:29 -05002023
2024 @Override
2025 public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
2026 enforceModifyPermission();
2027
2028 int returnValue = 0;
2029 try {
2030 AsyncResult result = (AsyncResult)sendRequest(CMD_INVOKE_OEM_RIL_REQUEST_RAW, oemReq);
2031 if(result.exception == null) {
2032 if (result.result != null) {
2033 byte[] responseData = (byte[])(result.result);
2034 if(responseData.length > oemResp.length) {
2035 Log.w(LOG_TAG, "Buffer to copy response too small: Response length is " +
2036 responseData.length + "bytes. Buffer Size is " +
2037 oemResp.length + "bytes.");
2038 }
2039 System.arraycopy(responseData, 0, oemResp, 0, responseData.length);
2040 returnValue = responseData.length;
2041 }
2042 } else {
2043 CommandException ex = (CommandException) result.exception;
2044 returnValue = ex.getCommandError().ordinal();
2045 if(returnValue > 0) returnValue *= -1;
2046 }
2047 } catch (RuntimeException e) {
2048 Log.w(LOG_TAG, "sendOemRilRequestRaw: Runtime Exception");
2049 returnValue = (CommandException.Error.GENERIC_FAILURE.ordinal());
2050 if(returnValue > 0) returnValue *= -1;
2051 }
2052
2053 return returnValue;
2054 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07002055}