blob: b392815c6d184424253922d2100f32588ff39133 [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,
445 IccOpenLogicalChannelResponse.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
454 int errorCode = IccOpenLogicalChannelResponse.UNKNOWN_ERROR;
455 if ((ar.exception != null) && (ar.exception instanceof CommandException)) {
456 if (ar.exception.getMessage().compareTo("MISSING_RESOURCE") == 0) {
457 errorCode = IccOpenLogicalChannelResponse.MISSING_RESOURCE;
458 } else if (ar.exception.getMessage().compareTo("NO_SUCH_ELEMENT") == 0) {
459 errorCode = IccOpenLogicalChannelResponse.NO_SUCH_ELEMENT;
460 }
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
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001093 public boolean setRadioPower(boolean turnOn) {
Wink Saville36469e72014-06-11 15:17:00 -07001094 return setRadioPowerUsingSubId(getDefaultSubscription(), turnOn);
1095 }
1096
1097 public boolean setRadioPowerUsingSubId(long subId, boolean turnOn) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001098 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001099 getPhone(subId).setRadioPower(turnOn);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001100 return true;
1101 }
1102
Wink Saville36469e72014-06-11 15:17:00 -07001103 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001104 public boolean enableDataConnectivity() {
1105 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001106 long subId = SubscriptionManager.getDefaultDataSubId();
1107 getPhone(subId).setDataEnabled(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001108 return true;
1109 }
1110
Wink Saville36469e72014-06-11 15:17:00 -07001111 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001112 public boolean disableDataConnectivity() {
1113 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001114 long subId = SubscriptionManager.getDefaultDataSubId();
1115 getPhone(subId).setDataEnabled(false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001116 return true;
1117 }
1118
Wink Saville36469e72014-06-11 15:17:00 -07001119 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001120 public boolean isDataConnectivityPossible() {
Wink Saville36469e72014-06-11 15:17:00 -07001121 long subId = SubscriptionManager.getDefaultDataSubId();
1122 return getPhone(subId).isDataConnectivityPossible();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001123 }
1124
1125 public boolean handlePinMmi(String dialString) {
Wink Saville36469e72014-06-11 15:17:00 -07001126 return handlePinMmiUsingSubId(getDefaultSubscription(), dialString);
1127 }
1128
1129 public boolean handlePinMmiUsingSubId(long subId, String dialString) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001130 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001131 return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001132 }
1133
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001134 public int getCallState() {
Wink Saville36469e72014-06-11 15:17:00 -07001135 return getCallStateUsingSubId(getDefaultSubscription());
1136 }
1137
1138 public int getCallStateUsingSubId(long subId) {
1139 return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001140 }
1141
1142 public int getDataState() {
Wink Saville36469e72014-06-11 15:17:00 -07001143 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1144 return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001145 }
1146
1147 public int getDataActivity() {
Wink Saville36469e72014-06-11 15:17:00 -07001148 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1149 return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001150 }
1151
1152 @Override
1153 public Bundle getCellLocation() {
1154 try {
1155 mApp.enforceCallingOrSelfPermission(
1156 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1157 } catch (SecurityException e) {
1158 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1159 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1160 // is the weaker precondition
1161 mApp.enforceCallingOrSelfPermission(
1162 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1163 }
1164
Jake Hambye994d462014-02-03 13:10:13 -08001165 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001166 if (DBG_LOC) log("getCellLocation: is active user");
1167 Bundle data = new Bundle();
1168 mPhone.getCellLocation().fillInNotifierBundle(data);
1169 return data;
1170 } else {
1171 if (DBG_LOC) log("getCellLocation: suppress non-active user");
1172 return null;
1173 }
1174 }
1175
1176 @Override
1177 public void enableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001178 enableLocationUpdatesUsingSubId(getDefaultSubscription());
1179 }
1180
1181 public void enableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001182 mApp.enforceCallingOrSelfPermission(
1183 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001184 getPhone(subId).enableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001185 }
1186
1187 @Override
1188 public void disableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001189 disableLocationUpdatesUsingSubId(getDefaultSubscription());
1190 }
1191
1192 public void disableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001193 mApp.enforceCallingOrSelfPermission(
1194 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001195 getPhone(subId).disableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001196 }
1197
1198 @Override
1199 @SuppressWarnings("unchecked")
1200 public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1201 try {
1202 mApp.enforceCallingOrSelfPermission(
1203 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1204 } catch (SecurityException e) {
1205 // If we have ACCESS_FINE_LOCATION permission, skip the check
1206 // for ACCESS_COARSE_LOCATION
1207 // A failure should throw the SecurityException from
1208 // ACCESS_COARSE_LOCATION since this is the weaker precondition
1209 mApp.enforceCallingOrSelfPermission(
1210 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1211 }
1212
1213 if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1214 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1215 return null;
1216 }
Jake Hambye994d462014-02-03 13:10:13 -08001217 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001218 if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1219
1220 ArrayList<NeighboringCellInfo> cells = null;
1221
1222 try {
1223 cells = (ArrayList<NeighboringCellInfo>) sendRequest(
Wink Saville36469e72014-06-11 15:17:00 -07001224 CMD_HANDLE_NEIGHBORING_CELL, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001225 } catch (RuntimeException e) {
Wink Saville36469e72014-06-11 15:17:00 -07001226 Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001227 }
1228 return cells;
1229 } else {
1230 if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1231 return null;
1232 }
1233 }
1234
1235
1236 @Override
1237 public List<CellInfo> getAllCellInfo() {
1238 try {
1239 mApp.enforceCallingOrSelfPermission(
1240 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1241 } catch (SecurityException e) {
1242 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1243 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1244 // is the weaker precondition
1245 mApp.enforceCallingOrSelfPermission(
1246 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1247 }
1248
Jake Hambye994d462014-02-03 13:10:13 -08001249 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001250 if (DBG_LOC) log("getAllCellInfo: is active user");
1251 return mPhone.getAllCellInfo();
1252 } else {
1253 if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1254 return null;
1255 }
1256 }
1257
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -07001258 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001259 public void setCellInfoListRate(int rateInMillis) {
1260 mPhone.setCellInfoListRate(rateInMillis);
1261 }
1262
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001263 //
1264 // Internal helper methods.
1265 //
1266
Jake Hambye994d462014-02-03 13:10:13 -08001267 private static boolean checkIfCallerIsSelfOrForegroundUser() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001268 boolean ok;
1269
1270 boolean self = Binder.getCallingUid() == Process.myUid();
1271 if (!self) {
1272 // Get the caller's user id then clear the calling identity
1273 // which will be restored in the finally clause.
1274 int callingUser = UserHandle.getCallingUserId();
1275 long ident = Binder.clearCallingIdentity();
1276
1277 try {
1278 // With calling identity cleared the current user is the foreground user.
1279 int foregroundUser = ActivityManager.getCurrentUser();
1280 ok = (foregroundUser == callingUser);
1281 if (DBG_LOC) {
1282 log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1283 + " callingUser=" + callingUser + " ok=" + ok);
1284 }
1285 } catch (Exception ex) {
1286 if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1287 ok = false;
1288 } finally {
1289 Binder.restoreCallingIdentity(ident);
1290 }
1291 } else {
1292 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1293 ok = true;
1294 }
1295 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1296 return ok;
1297 }
1298
1299 /**
1300 * Make sure the caller has the READ_PHONE_STATE permission.
1301 *
1302 * @throws SecurityException if the caller does not have the required permission
1303 */
1304 private void enforceReadPermission() {
1305 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
1306 }
1307
1308 /**
1309 * Make sure the caller has the MODIFY_PHONE_STATE permission.
1310 *
1311 * @throws SecurityException if the caller does not have the required permission
1312 */
1313 private void enforceModifyPermission() {
1314 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1315 }
1316
1317 /**
Junda Liua2e36012014-07-09 18:30:01 -07001318 * Make sure either system app or the caller has carrier privilege.
1319 *
1320 * @throws SecurityException if the caller does not have the required permission/privilege
1321 */
1322 private void enforceModifyPermissionOrCarrierPrivilege() {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001323 int permission = mApp.checkCallingOrSelfPermission(
1324 android.Manifest.permission.MODIFY_PHONE_STATE);
1325 if (permission == PackageManager.PERMISSION_GRANTED) {
1326 return;
1327 }
1328
1329 log("No modify permission, check carrier privilege next.");
1330 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1331 loge("No Carrier Privilege.");
1332 throw new SecurityException("No modify permission or carrier privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001333 }
1334 }
1335
1336 /**
1337 * Make sure the caller has carrier privilege.
1338 *
1339 * @throws SecurityException if the caller does not have the required permission
1340 */
1341 private void enforceCarrierPrivilege() {
1342 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001343 loge("No Carrier Privilege.");
1344 throw new SecurityException("No Carrier Privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001345 }
1346 }
1347
1348 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001349 * Make sure the caller has the CALL_PHONE permission.
1350 *
1351 * @throws SecurityException if the caller does not have the required permission
1352 */
1353 private void enforceCallPermission() {
1354 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1355 }
1356
Shishir Agrawal566b7612013-10-28 14:41:00 -07001357 /**
Gabriel Peal36ebb0d2014-03-20 09:20:43 -07001358 * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1359 *
1360 * @throws SecurityException if the caller does not have the required permission
1361 */
1362 private void enforcePrivilegedPhoneStatePermission() {
1363 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1364 null);
1365 }
1366
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001367 private String createTelUrl(String number) {
1368 if (TextUtils.isEmpty(number)) {
1369 return null;
1370 }
1371
Jake Hambye994d462014-02-03 13:10:13 -08001372 return "tel:" + number;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001373 }
1374
Ihab Awadf9e92732013-12-05 18:02:52 -08001375 private static void log(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001376 Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1377 }
1378
Ihab Awadf9e92732013-12-05 18:02:52 -08001379 private static void loge(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001380 Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1381 }
1382
1383 public int getActivePhoneType() {
Wink Saville36469e72014-06-11 15:17:00 -07001384 return getActivePhoneTypeUsingSubId(getDefaultSubscription());
1385 }
1386
1387 public int getActivePhoneTypeUsingSubId(long subId) {
1388 return getPhone(subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001389 }
1390
1391 /**
1392 * Returns the CDMA ERI icon index to display
1393 */
1394 public int getCdmaEriIconIndex() {
Wink Saville36469e72014-06-11 15:17:00 -07001395 return getCdmaEriIconIndexUsingSubId(getDefaultSubscription());
1396
1397 }
1398
1399 public int getCdmaEriIconIndexUsingSubId(long subId) {
1400 return getPhone(subId).getCdmaEriIconIndex();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001401 }
1402
1403 /**
1404 * Returns the CDMA ERI icon mode,
1405 * 0 - ON
1406 * 1 - FLASHING
1407 */
1408 public int getCdmaEriIconMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001409 return getCdmaEriIconModeUsingSubId(getDefaultSubscription());
1410 }
1411
1412 public int getCdmaEriIconModeUsingSubId(long subId) {
1413 return getPhone(subId).getCdmaEriIconMode();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001414 }
1415
1416 /**
1417 * Returns the CDMA ERI text,
1418 */
1419 public String getCdmaEriText() {
Wink Saville36469e72014-06-11 15:17:00 -07001420 return getCdmaEriTextUsingSubId(getDefaultSubscription());
1421 }
1422
1423 public String getCdmaEriTextUsingSubId(long subId) {
1424 return getPhone(subId).getCdmaEriText();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001425 }
1426
1427 /**
1428 * Returns true if CDMA provisioning needs to run.
1429 */
1430 public boolean needsOtaServiceProvisioning() {
1431 return mPhone.needsOtaServiceProvisioning();
1432 }
1433
1434 /**
1435 * Returns the unread count of voicemails
1436 */
1437 public int getVoiceMessageCount() {
Wink Saville36469e72014-06-11 15:17:00 -07001438 return getVoiceMessageCountUsingSubId(getDefaultSubscription());
1439 }
1440
1441 /**
1442 * Returns the unread count of voicemails for a subId
1443 */
1444 public int getVoiceMessageCountUsingSubId( long subId) {
1445 return getPhone(subId).getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001446 }
1447
1448 /**
1449 * Returns the data network type
1450 *
1451 * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1452 */
1453 @Override
1454 public int getNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001455 return getNetworkTypeUsingSubId(getDefaultSubscription());
1456 }
1457
1458 /**
1459 * Returns the network type for a subId
1460 */
1461 @Override
1462 public int getNetworkTypeUsingSubId(long subId) {
1463 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001464 }
1465
1466 /**
1467 * Returns the data network type
1468 */
1469 @Override
1470 public int getDataNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001471 return getDataNetworkTypeUsingSubId(getDefaultSubscription());
1472 }
1473
1474 /**
1475 * Returns the data network type for a subId
1476 */
1477 @Override
1478 public int getDataNetworkTypeUsingSubId(long subId) {
1479 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001480 }
1481
1482 /**
1483 * Returns the data network type
1484 */
1485 @Override
1486 public int getVoiceNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001487 return getVoiceNetworkTypeUsingSubId(getDefaultSubscription());
1488 }
1489
1490 /**
1491 * Returns the Voice network type for a subId
1492 */
1493 @Override
1494 public int getVoiceNetworkTypeUsingSubId(long subId) {
1495 return getPhone(subId).getServiceState().getVoiceNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001496 }
1497
1498 /**
1499 * @return true if a ICC card is present
1500 */
1501 public boolean hasIccCard() {
Wink Saville36469e72014-06-11 15:17:00 -07001502 // FIXME Make changes to pass defaultSimId of type int
1503 return hasIccCardUsingSlotId(getDefaultSubscription());
1504 }
1505
1506 /**
1507 * @return true if a ICC card is present for a slotId
1508 */
1509 public boolean hasIccCardUsingSlotId(long slotId) {
1510 return getPhone(slotId).getIccCard().hasIccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001511 }
1512
1513 /**
1514 * Return if the current radio is LTE on CDMA. This
1515 * is a tri-state return value as for a period of time
1516 * the mode may be unknown.
1517 *
1518 * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
Jake Hambye994d462014-02-03 13:10:13 -08001519 * or {@link Phone#LTE_ON_CDMA_TRUE}
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001520 */
1521 public int getLteOnCdmaMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001522 return getLteOnCdmaModeUsingSubId(getDefaultSubscription());
1523 }
1524
1525 public int getLteOnCdmaModeUsingSubId(long subId) {
1526 return getPhone(subId).getLteOnCdmaMode();
1527 }
1528
1529 public void setPhone(Phone phone) {
1530 mPhone = phone;
1531 }
1532
1533 /**
1534 * {@hide}
1535 * Returns Default subId, 0 in the case of single standby.
1536 */
1537 private long getDefaultSubscription() {
1538 return SubscriptionManager.getDefaultSubId();
1539 }
1540
1541 private long getPreferredVoiceSubscription() {
1542 return SubscriptionManager.getDefaultVoiceSubId();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001543 }
Ihab Awadf2177b72013-11-25 13:33:23 -08001544
1545 /**
1546 * @see android.telephony.TelephonyManager.WifiCallingChoices
1547 */
1548 public int getWhenToMakeWifiCalls() {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001549 return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1550 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
Ihab Awadf2177b72013-11-25 13:33:23 -08001551 }
1552
1553 /**
1554 * @see android.telephony.TelephonyManager.WifiCallingChoices
1555 */
1556 public void setWhenToMakeWifiCalls(int preference) {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001557 if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1558 Settings.System.putInt(mPhone.getContext().getContentResolver(),
1559 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
Ihab Awadf9e92732013-12-05 18:02:52 -08001560 }
1561
Sailesh Nepald1e68152013-12-12 19:08:02 -08001562 private static int getWhenToMakeWifiCallsDefaultPreference() {
1563 // TODO(sail): Use a build property to choose this value.
Evan Charlton9829e882013-12-19 15:30:38 -08001564 return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
Ihab Awadf2177b72013-11-25 13:33:23 -08001565 }
Shishir Agrawal69f68122013-12-16 17:25:49 -08001566
Shishir Agrawal566b7612013-10-28 14:41:00 -07001567 @Override
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001568 public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID) {
Junda Liua2e36012014-07-09 18:30:01 -07001569 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001570
1571 if (DBG) log("iccOpenLogicalChannel: " + AID);
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001572 IccOpenLogicalChannelResponse response = (IccOpenLogicalChannelResponse)sendRequest(
1573 CMD_OPEN_CHANNEL, AID);
1574 if (DBG) log("iccOpenLogicalChannel: " + response);
1575 return response;
Shishir Agrawal566b7612013-10-28 14:41:00 -07001576 }
1577
1578 @Override
1579 public boolean iccCloseLogicalChannel(int channel) {
Junda Liua2e36012014-07-09 18:30:01 -07001580 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001581
1582 if (DBG) log("iccCloseLogicalChannel: " + channel);
1583 if (channel < 0) {
1584 return false;
1585 }
Jake Hambye994d462014-02-03 13:10:13 -08001586 Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
Shishir Agrawal566b7612013-10-28 14:41:00 -07001587 if (DBG) log("iccCloseLogicalChannel: " + success);
1588 return success;
1589 }
1590
1591 @Override
1592 public String iccTransmitApduLogicalChannel(int channel, int cla,
1593 int command, int p1, int p2, int p3, String data) {
Junda Liua2e36012014-07-09 18:30:01 -07001594 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001595
1596 if (DBG) {
1597 log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1598 " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1599 " data=" + data);
1600 }
1601
1602 if (channel < 0) {
1603 return "";
1604 }
1605
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001606 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_LOGICAL_CHANNEL,
Shishir Agrawal566b7612013-10-28 14:41:00 -07001607 new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1608 if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1609
Shishir Agrawal566b7612013-10-28 14:41:00 -07001610 // Append the returned status code to the end of the response payload.
1611 String s = Integer.toHexString(
1612 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
Shishir Agrawal5ec14172014-08-05 17:05:45 -07001613 if (response.payload != null) {
1614 s = IccUtils.bytesToHexString(response.payload) + s;
1615 }
Shishir Agrawal566b7612013-10-28 14:41:00 -07001616 return s;
1617 }
Jake Hambye994d462014-02-03 13:10:13 -08001618
Evan Charltonc66da362014-05-16 14:06:40 -07001619 @Override
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001620 public String iccTransmitApduBasicChannel(int cla, int command, int p1, int p2,
1621 int p3, String data) {
1622 enforceModifyPermissionOrCarrierPrivilege();
1623
1624 if (DBG) {
1625 log("iccTransmitApduBasicChannel: cla=" + cla + " cmd=" + command + " p1="
1626 + p1 + " p2=" + p2 + " p3=" + p3 + " data=" + data);
1627 }
1628
1629 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_BASIC_CHANNEL,
1630 new IccAPDUArgument(0, cla, command, p1, p2, p3, data));
1631 if (DBG) log("iccTransmitApduBasicChannel: " + response);
1632
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001633 // Append the returned status code to the end of the response payload.
1634 String s = Integer.toHexString(
1635 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
Shishir Agrawal5ec14172014-08-05 17:05:45 -07001636 if (response.payload != null) {
1637 s = IccUtils.bytesToHexString(response.payload) + s;
1638 }
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001639 return s;
1640 }
1641
1642 @Override
1643 public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
1644 String filePath) {
1645 enforceModifyPermissionOrCarrierPrivilege();
1646
1647 if (DBG) {
1648 log("Exchange SIM_IO " + fileID + ":" + command + " " +
1649 p1 + " " + p2 + " " + p3 + ":" + filePath);
1650 }
1651
1652 IccIoResult response =
1653 (IccIoResult)sendRequest(CMD_EXCHANGE_SIM_IO,
1654 new IccAPDUArgument(fileID, command, -1, p1, p2, p3, filePath));
1655
1656 if (DBG) {
1657 log("Exchange SIM_IO [R]" + response);
1658 }
1659
1660 byte[] result = null;
1661 int length = 2;
1662 if (response.payload != null) {
1663 length = 2 + response.payload.length;
1664 result = new byte[length];
1665 System.arraycopy(response.payload, 0, result, 0, response.payload.length);
1666 } else {
1667 result = new byte[length];
1668 }
1669
1670 result[length - 1] = (byte) response.sw2;
1671 result[length - 2] = (byte) response.sw1;
1672 return result;
1673 }
1674
1675 @Override
Evan Charltonc66da362014-05-16 14:06:40 -07001676 public String sendEnvelopeWithStatus(String content) {
Junda Liua2e36012014-07-09 18:30:01 -07001677 enforceModifyPermissionOrCarrierPrivilege();
Evan Charltonc66da362014-05-16 14:06:40 -07001678
1679 IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
1680 if (response.payload == null) {
1681 return "";
1682 }
1683
1684 // Append the returned status code to the end of the response payload.
1685 String s = Integer.toHexString(
1686 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1687 s = IccUtils.bytesToHexString(response.payload) + s;
1688 return s;
1689 }
1690
Jake Hambye994d462014-02-03 13:10:13 -08001691 /**
1692 * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1693 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1694 *
1695 * @param itemID the ID of the item to read
1696 * @return the NV item as a String, or null on error.
1697 */
1698 @Override
1699 public String nvReadItem(int itemID) {
Junda Liua2e36012014-07-09 18:30:01 -07001700 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001701 if (DBG) log("nvReadItem: item " + itemID);
1702 String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
1703 if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
1704 return value;
1705 }
1706
1707 /**
1708 * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1709 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1710 *
1711 * @param itemID the ID of the item to read
1712 * @param itemValue the value to write, as a String
1713 * @return true on success; false on any failure
1714 */
1715 @Override
1716 public boolean nvWriteItem(int itemID, String itemValue) {
Junda Liua2e36012014-07-09 18:30:01 -07001717 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001718 if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
1719 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
1720 new Pair<Integer, String>(itemID, itemValue));
1721 if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
1722 return success;
1723 }
1724
1725 /**
1726 * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
1727 * Used for device configuration by some CDMA operators.
1728 *
1729 * @param preferredRoamingList byte array containing the new PRL
1730 * @return true on success; false on any failure
1731 */
1732 @Override
1733 public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
Junda Liua2e36012014-07-09 18:30:01 -07001734 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001735 if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
1736 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
1737 if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
1738 return success;
1739 }
1740
1741 /**
1742 * Perform the specified type of NV config reset.
1743 * Used for device configuration by some CDMA operators.
1744 *
1745 * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
1746 * @return true on success; false on any failure
1747 */
1748 @Override
1749 public boolean nvResetConfig(int resetType) {
Junda Liua2e36012014-07-09 18:30:01 -07001750 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001751 if (DBG) log("nvResetConfig: type " + resetType);
1752 Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
1753 if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
1754 return success;
1755 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001756
1757 /**
Wink Saville36469e72014-06-11 15:17:00 -07001758 * {@hide}
1759 * Returns Default sim, 0 in the case of single standby.
1760 */
1761 public int getDefaultSim() {
1762 //TODO Need to get it from Telephony Devcontroller
1763 return 0;
1764 }
1765
ram87fca6f2014-07-18 18:58:44 +05301766 public String[] getPcscfAddress(String apnType) {
Wink Saville36469e72014-06-11 15:17:00 -07001767 enforceReadPermission();
ram87fca6f2014-07-18 18:58:44 +05301768 return mPhone.getPcscfAddress(apnType);
Wink Saville36469e72014-06-11 15:17:00 -07001769 }
1770
1771 public void setImsRegistrationState(boolean registered) {
1772 enforceModifyPermission();
1773 mPhone.setImsRegistrationState(registered);
1774 }
1775
1776 /**
Junda Liu84d15a22014-07-02 11:21:04 -07001777 * Get the calculated preferred network type.
1778 * Used for debugging incorrect network type.
1779 *
1780 * @return the preferred network type, defined in RILConstants.java.
1781 */
1782 @Override
1783 public int getCalculatedPreferredNetworkType() {
1784 enforceReadPermission();
1785 return PhoneFactory.calculatePreferredNetworkType(mPhone.getContext());
1786 }
1787
1788 /**
Jake Hamby7c27be32014-03-03 13:25:59 -08001789 * Get the preferred network type.
1790 * Used for device configuration by some CDMA operators.
1791 *
1792 * @return the preferred network type, defined in RILConstants.java.
1793 */
1794 @Override
1795 public int getPreferredNetworkType() {
Junda Liua2e36012014-07-09 18:30:01 -07001796 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001797 if (DBG) log("getPreferredNetworkType");
1798 int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null);
1799 int networkType = (result != null ? result[0] : -1);
1800 if (DBG) log("getPreferredNetworkType: " + networkType);
1801 return networkType;
1802 }
1803
1804 /**
1805 * Set the preferred network type.
1806 * Used for device configuration by some CDMA operators.
1807 *
1808 * @param networkType the preferred network type, defined in RILConstants.java.
1809 * @return true on success; false on any failure.
1810 */
1811 @Override
1812 public boolean setPreferredNetworkType(int networkType) {
Junda Liua2e36012014-07-09 18:30:01 -07001813 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001814 if (DBG) log("setPreferredNetworkType: type " + networkType);
1815 Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType);
1816 if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
Junda Liu80bc0d12014-07-14 16:36:44 -07001817 if (success) {
1818 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1819 Settings.Global.PREFERRED_NETWORK_MODE, networkType);
1820 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001821 return success;
1822 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001823
1824 /**
Junda Liu787bc7e2014-06-30 13:38:02 -07001825 * Set the CDMA subscription source.
1826 * Used for device supporting both NV and RUIM for CDMA.
1827 *
1828 * @param subscriptionType the subscription type, 0 for RUIM, 1 for NV.
1829 * @return true on success; false on any failure.
1830 */
1831 @Override
1832 public boolean setCdmaSubscription(int subscriptionType) {
Junda Liua2e36012014-07-09 18:30:01 -07001833 enforceModifyPermissionOrCarrierPrivilege();
Junda Liu787bc7e2014-06-30 13:38:02 -07001834 if (DBG) log("setCdmaSubscription: type " + subscriptionType);
1835 if (subscriptionType != mPhone.CDMA_SUBSCRIPTION_RUIM_SIM &&
1836 subscriptionType != mPhone.CDMA_SUBSCRIPTION_NV) {
1837 loge("setCdmaSubscription: unsupported subscriptionType.");
1838 return false;
1839 }
1840 Boolean success = (Boolean) sendRequest(CMD_SET_CDMA_SUBSCRIPTION, subscriptionType);
1841 if (DBG) log("setCdmaSubscription: " + (success ? "ok" : "fail"));
1842 if (success) {
1843 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1844 Settings.Global.CDMA_SUBSCRIPTION_MODE, subscriptionType);
1845 }
1846 return success;
1847 }
1848
1849 /**
Robert Greenwalted86e582014-05-21 20:03:20 -07001850 * Set mobile data enabled
1851 * Used by the user through settings etc to turn on/off mobile data
1852 *
1853 * @param enable {@code true} turn turn data on, else {@code false}
1854 */
1855 @Override
1856 public void setDataEnabled(boolean enable) {
1857 enforceModifyPermission();
1858 mPhone.setDataEnabled(enable);
1859 }
1860
1861 /**
Robert Greenwalt646120a2014-05-23 11:54:03 -07001862 * Get whether mobile data is enabled.
1863 *
1864 * Note that this used to be available from ConnectivityService, gated by
1865 * ACCESS_NETWORK_STATE permission, so this will accept either that or
1866 * our MODIFY_PHONE_STATE.
Robert Greenwalted86e582014-05-21 20:03:20 -07001867 *
1868 * @return {@code true} if data is enabled else {@code false}
1869 */
1870 @Override
1871 public boolean getDataEnabled() {
Robert Greenwalt646120a2014-05-23 11:54:03 -07001872 try {
1873 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
1874 null);
1875 } catch (Exception e) {
1876 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
1877 null);
1878 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001879 return mPhone.getDataEnabled();
1880 }
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001881
1882 @Override
1883 public int hasCarrierPrivileges() {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001884 UiccCard card = UiccController.getInstance().getUiccCard();
1885 if (card == null) {
1886 loge("hasCarrierPrivileges: No UICC");
1887 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1888 }
1889 return card.getCarrierPrivilegeStatusForCurrentTransaction(
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001890 mPhone.getContext().getPackageManager());
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001891 }
Junda Liu29340342014-07-10 15:23:27 -07001892
1893 @Override
Shishir Agrawal6d5a2852014-07-11 16:32:57 -07001894 public int checkCarrierPrivilegesForPackage(String pkgname) {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001895 UiccCard card = UiccController.getInstance().getUiccCard();
1896 if (card == null) {
1897 loge("checkCarrierPrivilegesForPackage: No UICC");
1898 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1899 }
1900 return card.getCarrierPrivilegeStatus(mPhone.getContext().getPackageManager(), pkgname);
Junda Liu29340342014-07-10 15:23:27 -07001901 }
Derek Tan89e89d42014-07-08 17:00:10 -07001902
1903 @Override
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001904 public List<String> getCarrierPackageNamesForBroadcastIntent(Intent intent) {
1905 UiccCard card = UiccController.getInstance().getUiccCard();
1906 if (card == null) {
1907 loge("getCarrierPackageNamesForBroadcastIntent: No UICC");
1908 return null ;
1909 }
1910 return card.getCarrierPackageNamesForBroadcastIntent(
1911 mPhone.getContext().getPackageManager(), intent);
1912 }
1913
1914 @Override
Derek Tan89e89d42014-07-08 17:00:10 -07001915 public void enableSimplifiedNetworkSettings(long subId, boolean enable) {
Derek Tan352d8cd2014-07-12 12:57:11 -07001916 enforceModifyPermissionOrCarrierPrivilege();
Derek Tan89e89d42014-07-08 17:00:10 -07001917 if (enable) {
1918 mSimplifiedNetworkSettings.add(subId);
1919 } else {
1920 mSimplifiedNetworkSettings.remove(subId);
1921 }
1922 }
1923
1924 @Override
1925 public boolean getSimplifiedNetworkSettingsEnabled(long subId) {
1926 enforceReadPermission();
1927 return mSimplifiedNetworkSettings.contains(subId);
1928 }
Derek Tan7226c842014-07-02 17:42:23 -07001929
1930 @Override
1931 public void setLine1NumberForDisplay(long subId, String alphaTag, String number) {
Derek Tan352d8cd2014-07-12 12:57:11 -07001932 enforceModifyPermissionOrCarrierPrivilege();
Derek Tan7226c842014-07-02 17:42:23 -07001933 mAdnRecordsForDisplay.put(subId, new AdnRecord(alphaTag, number));
1934 }
1935
1936 @Override
1937 public String getLine1NumberForDisplay(long subId) {
1938 enforceReadPermission();
1939 if (!mAdnRecordsForDisplay.containsKey(subId)) {
1940 return null;
1941 }
1942 AdnRecord adnRecord = mAdnRecordsForDisplay.get(subId);
1943 if (adnRecord.getNumber() == null || adnRecord.getNumber().isEmpty()) {
1944 return null;
1945 }
1946 return adnRecord.getNumber();
1947 }
1948
1949 @Override
1950 public String getLine1AlphaTagForDisplay(long subId) {
1951 enforceReadPermission();
1952 if (!mAdnRecordsForDisplay.containsKey(subId)) {
1953 return null;
1954 }
1955 AdnRecord adnRecord = mAdnRecordsForDisplay.get(subId);
1956 if (adnRecord.getAlphaTag() == null || adnRecord.getAlphaTag().isEmpty()) {
1957 return null;
1958 }
1959 return adnRecord.getAlphaTag();
1960 }
Shishir Agrawalb1ebf8c2014-07-17 16:32:41 -07001961
1962 @Override
1963 public boolean setOperatorBrandOverride(String iccId, String brand) {
1964 enforceModifyPermissionOrCarrierPrivilege();
1965 return mPhone.setOperatorBrandOverride(iccId, brand);
1966 }
Steven Liu4bf01bc2014-07-17 11:05:29 -05001967
1968 @Override
1969 public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
1970 enforceModifyPermission();
1971
1972 int returnValue = 0;
1973 try {
1974 AsyncResult result = (AsyncResult)sendRequest(CMD_INVOKE_OEM_RIL_REQUEST_RAW, oemReq);
1975 if(result.exception == null) {
1976 if (result.result != null) {
1977 byte[] responseData = (byte[])(result.result);
1978 if(responseData.length > oemResp.length) {
1979 Log.w(LOG_TAG, "Buffer to copy response too small: Response length is " +
1980 responseData.length + "bytes. Buffer Size is " +
1981 oemResp.length + "bytes.");
1982 }
1983 System.arraycopy(responseData, 0, oemResp, 0, responseData.length);
1984 returnValue = responseData.length;
1985 }
1986 } else {
1987 CommandException ex = (CommandException) result.exception;
1988 returnValue = ex.getCommandError().ordinal();
1989 if(returnValue > 0) returnValue *= -1;
1990 }
1991 } catch (RuntimeException e) {
1992 Log.w(LOG_TAG, "sendOemRilRequestRaw: Runtime Exception");
1993 returnValue = (CommandException.Error.GENERIC_FAILURE.ordinal());
1994 if(returnValue > 0) returnValue *= -1;
1995 }
1996
1997 return returnValue;
1998 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001999}