blob: 02a9c1fa00ba9768c1f6304cf4e6a55629e0e643 [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 }
465 synchronized (request) {
466 request.notifyAll();
467 }
468 break;
469
470 case CMD_CLOSE_CHANNEL:
471 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700472 if (uiccCard == null) {
473 loge("iccCloseLogicalChannel: No UICC");
474 request.result = new IccIoResult(0x6F, 0, (byte[])null);
475 synchronized (request) {
476 request.notifyAll();
477 }
478 } else {
479 onCompleted = obtainMessage(EVENT_CLOSE_CHANNEL_DONE, request);
480 uiccCard.iccCloseLogicalChannel((Integer) request.argument, onCompleted);
481 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700482 break;
483
484 case EVENT_CLOSE_CHANNEL_DONE:
Jake Hambye994d462014-02-03 13:10:13 -0800485 handleNullReturnEvent(msg, "iccCloseLogicalChannel");
486 break;
487
488 case CMD_NV_READ_ITEM:
489 request = (MainThreadRequest) msg.obj;
490 onCompleted = obtainMessage(EVENT_NV_READ_ITEM_DONE, request);
491 mPhone.nvReadItem((Integer) request.argument, onCompleted);
492 break;
493
494 case EVENT_NV_READ_ITEM_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700495 ar = (AsyncResult) msg.obj;
496 request = (MainThreadRequest) ar.userObj;
Jake Hambye994d462014-02-03 13:10:13 -0800497 if (ar.exception == null && ar.result != null) {
498 request.result = ar.result; // String
Shishir Agrawal566b7612013-10-28 14:41:00 -0700499 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800500 request.result = "";
501 if (ar.result == null) {
502 loge("nvReadItem: Empty response");
503 } else if (ar.exception instanceof CommandException) {
504 loge("nvReadItem: CommandException: " +
505 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700506 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800507 loge("nvReadItem: Unknown exception");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700508 }
509 }
510 synchronized (request) {
511 request.notifyAll();
512 }
513 break;
514
Jake Hambye994d462014-02-03 13:10:13 -0800515 case CMD_NV_WRITE_ITEM:
516 request = (MainThreadRequest) msg.obj;
517 onCompleted = obtainMessage(EVENT_NV_WRITE_ITEM_DONE, request);
518 Pair<Integer, String> idValue = (Pair<Integer, String>) request.argument;
519 mPhone.nvWriteItem(idValue.first, idValue.second, onCompleted);
520 break;
521
522 case EVENT_NV_WRITE_ITEM_DONE:
523 handleNullReturnEvent(msg, "nvWriteItem");
524 break;
525
526 case CMD_NV_WRITE_CDMA_PRL:
527 request = (MainThreadRequest) msg.obj;
528 onCompleted = obtainMessage(EVENT_NV_WRITE_CDMA_PRL_DONE, request);
529 mPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
530 break;
531
532 case EVENT_NV_WRITE_CDMA_PRL_DONE:
533 handleNullReturnEvent(msg, "nvWriteCdmaPrl");
534 break;
535
536 case CMD_NV_RESET_CONFIG:
537 request = (MainThreadRequest) msg.obj;
538 onCompleted = obtainMessage(EVENT_NV_RESET_CONFIG_DONE, request);
539 mPhone.nvResetConfig((Integer) request.argument, onCompleted);
540 break;
541
542 case EVENT_NV_RESET_CONFIG_DONE:
543 handleNullReturnEvent(msg, "nvResetConfig");
544 break;
545
Jake Hamby7c27be32014-03-03 13:25:59 -0800546 case CMD_GET_PREFERRED_NETWORK_TYPE:
547 request = (MainThreadRequest) msg.obj;
548 onCompleted = obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE_DONE, request);
549 mPhone.getPreferredNetworkType(onCompleted);
550 break;
551
552 case EVENT_GET_PREFERRED_NETWORK_TYPE_DONE:
553 ar = (AsyncResult) msg.obj;
554 request = (MainThreadRequest) ar.userObj;
555 if (ar.exception == null && ar.result != null) {
556 request.result = ar.result; // Integer
557 } else {
558 request.result = -1;
559 if (ar.result == null) {
560 loge("getPreferredNetworkType: Empty response");
561 } else if (ar.exception instanceof CommandException) {
562 loge("getPreferredNetworkType: CommandException: " +
563 ar.exception);
564 } else {
565 loge("getPreferredNetworkType: Unknown exception");
566 }
567 }
568 synchronized (request) {
569 request.notifyAll();
570 }
571 break;
572
573 case CMD_SET_PREFERRED_NETWORK_TYPE:
574 request = (MainThreadRequest) msg.obj;
575 onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);
576 int networkType = (Integer) request.argument;
577 mPhone.setPreferredNetworkType(networkType, onCompleted);
578 break;
579
580 case EVENT_SET_PREFERRED_NETWORK_TYPE_DONE:
581 handleNullReturnEvent(msg, "setPreferredNetworkType");
582 break;
583
Junda Liu787bc7e2014-06-30 13:38:02 -0700584 case CMD_SET_CDMA_SUBSCRIPTION:
585 request = (MainThreadRequest) msg.obj;
586 onCompleted = obtainMessage(EVENT_SET_CDMA_SUBSCRIPTION_DONE, request);
587 int subscriptionType = (Integer) request.argument;
588 mPhone.setCdmaSubscription(subscriptionType, onCompleted);
589 break;
590
591 case EVENT_SET_CDMA_SUBSCRIPTION_DONE:
592 handleNullReturnEvent(msg, "setCdmaSubscription");
593 break;
594
Steven Liu4bf01bc2014-07-17 11:05:29 -0500595 case CMD_INVOKE_OEM_RIL_REQUEST_RAW:
596 request = (MainThreadRequest)msg.obj;
597 onCompleted = obtainMessage(EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE, request);
598 mPhone.invokeOemRilRequestRaw((byte[])request.argument, onCompleted);
599 break;
600
601 case EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE:
602 ar = (AsyncResult)msg.obj;
603 request = (MainThreadRequest)ar.userObj;
604 request.result = ar;
605 synchronized (request) {
606 request.notifyAll();
607 }
608 break;
609
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700610 default:
611 Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
612 break;
613 }
614 }
Jake Hambye994d462014-02-03 13:10:13 -0800615
616 private void handleNullReturnEvent(Message msg, String command) {
617 AsyncResult ar = (AsyncResult) msg.obj;
618 MainThreadRequest request = (MainThreadRequest) ar.userObj;
619 if (ar.exception == null) {
620 request.result = true;
621 } else {
622 request.result = false;
623 if (ar.exception instanceof CommandException) {
624 loge(command + ": CommandException: " + ar.exception);
625 } else {
626 loge(command + ": Unknown exception");
627 }
628 }
629 synchronized (request) {
630 request.notifyAll();
631 }
632 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700633 }
634
635 /**
636 * Posts the specified command to be executed on the main thread,
637 * waits for the request to complete, and returns the result.
638 * @see #sendRequestAsync
639 */
640 private Object sendRequest(int command, Object argument) {
Santos Cordon500b0e02014-06-17 10:33:33 -0700641 return sendRequest(command, argument, null);
Wink Saville36469e72014-06-11 15:17:00 -0700642 }
643
644 /**
645 * Posts the specified command to be executed on the main thread,
646 * waits for the request to complete, and returns the result.
647 * @see #sendRequestAsync
648 */
649 private Object sendRequest(int command, Object argument, Object argument2) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700650 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
651 throw new RuntimeException("This method will deadlock if called from the main thread.");
652 }
653
654 MainThreadRequest request = new MainThreadRequest(argument);
655 Message msg = mMainThreadHandler.obtainMessage(command, request);
656 msg.sendToTarget();
657
658 // Wait for the request to complete
659 synchronized (request) {
660 while (request.result == null) {
661 try {
662 request.wait();
663 } catch (InterruptedException e) {
664 // Do nothing, go back and wait until the request is complete
665 }
666 }
667 }
668 return request.result;
669 }
670
671 /**
672 * Asynchronous ("fire and forget") version of sendRequest():
673 * Posts the specified command to be executed on the main thread, and
674 * returns immediately.
675 * @see #sendRequest
676 */
677 private void sendRequestAsync(int command) {
678 mMainThreadHandler.sendEmptyMessage(command);
679 }
680
681 /**
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -0700682 * Same as {@link #sendRequestAsync(int)} except it takes an argument.
683 * @see {@link #sendRequest(int,Object)}
684 */
685 private void sendRequestAsync(int command, Object argument) {
686 MainThreadRequest request = new MainThreadRequest(argument);
687 Message msg = mMainThreadHandler.obtainMessage(command, request);
688 msg.sendToTarget();
689 }
690
691 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700692 * Initialize the singleton PhoneInterfaceManager instance.
693 * This is only done once, at startup, from PhoneApp.onCreate().
694 */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700695 /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700696 synchronized (PhoneInterfaceManager.class) {
697 if (sInstance == null) {
Sailesh Nepal194161e2014-07-03 08:57:44 -0700698 sInstance = new PhoneInterfaceManager(app, phone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700699 } else {
700 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
701 }
702 return sInstance;
703 }
704 }
705
706 /** Private constructor; @see init() */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700707 private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700708 mApp = app;
709 mPhone = phone;
710 mCM = PhoneGlobals.getInstance().mCM;
Derek Tan89e89d42014-07-08 17:00:10 -0700711 mSimplifiedNetworkSettings = new HashSet<Long>();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700712 mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
713 mMainThreadHandler = new MainThreadHandler();
Derek Tan7226c842014-07-02 17:42:23 -0700714 mAdnRecordsForDisplay = new HashMap<Long, AdnRecord>();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700715 publish();
716 }
717
718 private void publish() {
719 if (DBG) log("publish: " + this);
720
721 ServiceManager.addService("phone", this);
722 }
723
Wink Saville36469e72014-06-11 15:17:00 -0700724 // returns phone associated with the subId.
725 // getPhone(0) returns default phone in single SIM mode.
726 private Phone getPhone(long subId) {
727 // FIXME: hack for the moment
728 return mPhone;
729 // return PhoneUtils.getPhoneUsingSubId(subId);
730 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700731 //
732 // Implementation of the ITelephony interface.
733 //
734
735 public void dial(String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700736 dialUsingSubId(getPreferredVoiceSubscription(), number);
737 }
738
739 public void dialUsingSubId(long subId, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700740 if (DBG) log("dial: " + number);
741 // No permission check needed here: This is just a wrapper around the
742 // ACTION_DIAL intent, which is available to any app since it puts up
743 // the UI before it does anything.
744
745 String url = createTelUrl(number);
746 if (url == null) {
747 return;
748 }
749
750 // PENDING: should we just silently fail if phone is offhook or ringing?
Wink Saville36469e72014-06-11 15:17:00 -0700751 PhoneConstants.State state = mCM.getState(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700752 if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
753 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
754 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Wink Saville36469e72014-06-11 15:17:00 -0700755 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700756 mApp.startActivity(intent);
757 }
758 }
759
760 public void call(String callingPackage, String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700761 callUsingSubId(getPreferredVoiceSubscription(), callingPackage, number);
762 }
763
764 public void callUsingSubId(long subId, String callingPackage, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700765 if (DBG) log("call: " + number);
766
767 // This is just a wrapper around the ACTION_CALL intent, but we still
768 // need to do a permission check since we're calling startActivity()
769 // from the context of the phone app.
770 enforceCallPermission();
771
772 if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
773 != AppOpsManager.MODE_ALLOWED) {
774 return;
775 }
776
777 String url = createTelUrl(number);
778 if (url == null) {
779 return;
780 }
781
782 Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
Wink Saville36469e72014-06-11 15:17:00 -0700783 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700784 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
785 mApp.startActivity(intent);
786 }
787
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700788 /**
789 * End a call based on call state
790 * @return true is a call was ended
791 */
792 public boolean endCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700793 return endCallUsingSubId(getDefaultSubscription());
794 }
795
796 /**
797 * End a call based on the call state of the subId
798 * @return true is a call was ended
799 */
800 public boolean endCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700801 enforceCallPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700802 return (Boolean) sendRequest(CMD_END_CALL, subId, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700803 }
804
805 public void answerRingingCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700806 answerRingingCallUsingSubId(getDefaultSubscription());
807 }
808
809 public void answerRingingCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700810 if (DBG) log("answerRingingCall...");
811 // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
812 // but that can probably wait till the big TelephonyManager API overhaul.
813 // For now, protect this call with the MODIFY_PHONE_STATE permission.
814 enforceModifyPermission();
815 sendRequestAsync(CMD_ANSWER_RINGING_CALL);
816 }
817
818 /**
819 * Make the actual telephony calls to implement answerRingingCall().
820 * This should only be called from the main thread of the Phone app.
821 * @see #answerRingingCall
822 *
823 * TODO: it would be nice to return true if we answered the call, or
824 * false if there wasn't actually a ringing incoming call, or some
825 * other error occurred. (In other words, pass back the return value
826 * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
827 * But that would require calling this method via sendRequest() rather
828 * than sendRequestAsync(), and right now we don't actually *need* that
829 * return value, so let's just return void for now.
830 */
831 private void answerRingingCallInternal() {
832 final boolean hasRingingCall = !mPhone.getRingingCall().isIdle();
833 if (hasRingingCall) {
834 final boolean hasActiveCall = !mPhone.getForegroundCall().isIdle();
835 final boolean hasHoldingCall = !mPhone.getBackgroundCall().isIdle();
836 if (hasActiveCall && hasHoldingCall) {
837 // Both lines are in use!
838 // TODO: provide a flag to let the caller specify what
839 // policy to use if both lines are in use. (The current
840 // behavior is hardwired to "answer incoming, end ongoing",
841 // which is how the CALL button is specced to behave.)
842 PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
843 return;
844 } else {
845 // answerCall() will automatically hold the current active
846 // call, if there is one.
847 PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
848 return;
849 }
850 } else {
851 // No call was ringing.
852 return;
853 }
854 }
855
856 public void silenceRinger() {
857 if (DBG) log("silenceRinger...");
858 // TODO: find a more appropriate permission to check here.
859 // (That can probably wait till the big TelephonyManager API overhaul.
860 // For now, protect this call with the MODIFY_PHONE_STATE permission.)
861 enforceModifyPermission();
862 sendRequestAsync(CMD_SILENCE_RINGER);
863 }
864
865 /**
866 * Internal implemenation of silenceRinger().
867 * This should only be called from the main thread of the Phone app.
868 * @see #silenceRinger
869 */
870 private void silenceRingerInternal() {
871 if ((mCM.getState() == PhoneConstants.State.RINGING)
872 && mApp.notifier.isRinging()) {
873 // Ringer is actually playing, so silence it.
874 if (DBG) log("silenceRingerInternal: silencing...");
875 mApp.notifier.silenceRinger();
876 }
877 }
878
879 public boolean isOffhook() {
Wink Saville36469e72014-06-11 15:17:00 -0700880 return isOffhookUsingSubId(getDefaultSubscription());
881 }
882
883 public boolean isOffhookUsingSubId(long subId) {
884 return (getPhone(subId).getState() == PhoneConstants.State.OFFHOOK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700885 }
886
887 public boolean isRinging() {
Wink Saville36469e72014-06-11 15:17:00 -0700888 return (isRingingUsingSubId(getDefaultSubscription()));
889 }
890
891 public boolean isRingingUsingSubId(long subId) {
892 return (getPhone(subId).getState() == PhoneConstants.State.RINGING);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700893 }
894
895 public boolean isIdle() {
Wink Saville36469e72014-06-11 15:17:00 -0700896 return isIdleUsingSubId(getDefaultSubscription());
897 }
898
899 public boolean isIdleUsingSubId(long subId) {
900 return (getPhone(subId).getState() == PhoneConstants.State.IDLE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700901 }
902
903 public boolean isSimPinEnabled() {
904 enforceReadPermission();
905 return (PhoneGlobals.getInstance().isSimPinEnabled());
906 }
907
908 public boolean supplyPin(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700909 return supplyPinUsingSubId(getDefaultSubscription(), pin);
910 }
911
912 public boolean supplyPinUsingSubId(long subId, String pin) {
913 int [] resultArray = supplyPinReportResultUsingSubId(subId, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700914 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
915 }
916
917 public boolean supplyPuk(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700918 return supplyPukUsingSubId(getDefaultSubscription(), puk, pin);
919 }
920
921 public boolean supplyPukUsingSubId(long subId, String puk, String pin) {
922 int [] resultArray = supplyPukReportResultUsingSubId(subId, puk, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700923 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
924 }
925
926 /** {@hide} */
927 public int[] supplyPinReportResult(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700928 return supplyPinReportResultUsingSubId(getDefaultSubscription(), pin);
929 }
930
931 public int[] supplyPinReportResultUsingSubId(long subId, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700932 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700933 final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700934 checkSimPin.start();
935 return checkSimPin.unlockSim(null, pin);
936 }
937
Wink Saville9de0f752013-10-22 19:04:03 -0700938 /** {@hide} */
939 public int[] supplyPukReportResult(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700940 return supplyPukReportResultUsingSubId(getDefaultSubscription(), puk, pin);
941 }
942
943 public int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700944 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700945 final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700946 checkSimPuk.start();
947 return checkSimPuk.unlockSim(puk, pin);
948 }
949
950 /**
Wink Saville9de0f752013-10-22 19:04:03 -0700951 * Helper thread to turn async call to SimCard#supplyPin into
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700952 * a synchronous one.
953 */
954 private static class UnlockSim extends Thread {
955
956 private final IccCard mSimCard;
957
958 private boolean mDone = false;
Wink Saville9de0f752013-10-22 19:04:03 -0700959 private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
960 private int mRetryCount = -1;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700961
962 // For replies from SimCard interface
963 private Handler mHandler;
964
965 // For async handler to identify request type
966 private static final int SUPPLY_PIN_COMPLETE = 100;
967
968 public UnlockSim(IccCard simCard) {
969 mSimCard = simCard;
970 }
971
972 @Override
973 public void run() {
974 Looper.prepare();
975 synchronized (UnlockSim.this) {
976 mHandler = new Handler() {
977 @Override
978 public void handleMessage(Message msg) {
979 AsyncResult ar = (AsyncResult) msg.obj;
980 switch (msg.what) {
981 case SUPPLY_PIN_COMPLETE:
982 Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
983 synchronized (UnlockSim.this) {
Wink Saville9de0f752013-10-22 19:04:03 -0700984 mRetryCount = msg.arg1;
985 if (ar.exception != null) {
986 if (ar.exception instanceof CommandException &&
987 ((CommandException)(ar.exception)).getCommandError()
988 == CommandException.Error.PASSWORD_INCORRECT) {
989 mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
990 } else {
991 mResult = PhoneConstants.PIN_GENERAL_FAILURE;
992 }
993 } else {
994 mResult = PhoneConstants.PIN_RESULT_SUCCESS;
995 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700996 mDone = true;
997 UnlockSim.this.notifyAll();
998 }
999 break;
1000 }
1001 }
1002 };
1003 UnlockSim.this.notifyAll();
1004 }
1005 Looper.loop();
1006 }
1007
1008 /*
1009 * Use PIN or PUK to unlock SIM card
1010 *
1011 * If PUK is null, unlock SIM card with PIN
1012 *
1013 * If PUK is not null, unlock SIM card with PUK and set PIN code
1014 */
Wink Saville9de0f752013-10-22 19:04:03 -07001015 synchronized int[] unlockSim(String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001016
1017 while (mHandler == null) {
1018 try {
1019 wait();
1020 } catch (InterruptedException e) {
1021 Thread.currentThread().interrupt();
1022 }
1023 }
1024 Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
1025
1026 if (puk == null) {
1027 mSimCard.supplyPin(pin, callback);
1028 } else {
1029 mSimCard.supplyPuk(puk, pin, callback);
1030 }
1031
1032 while (!mDone) {
1033 try {
1034 Log.d(LOG_TAG, "wait for done");
1035 wait();
1036 } catch (InterruptedException e) {
1037 // Restore the interrupted status
1038 Thread.currentThread().interrupt();
1039 }
1040 }
1041 Log.d(LOG_TAG, "done");
Wink Saville9de0f752013-10-22 19:04:03 -07001042 int[] resultArray = new int[2];
1043 resultArray[0] = mResult;
1044 resultArray[1] = mRetryCount;
1045 return resultArray;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001046 }
1047 }
1048
1049 public void updateServiceLocation() {
Wink Saville36469e72014-06-11 15:17:00 -07001050 updateServiceLocationUsingSubId(getDefaultSubscription());
1051
1052 }
1053
1054 public void updateServiceLocationUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001055 // No permission check needed here: this call is harmless, and it's
1056 // needed for the ServiceState.requestStateUpdate() call (which is
1057 // already intentionally exposed to 3rd parties.)
Wink Saville36469e72014-06-11 15:17:00 -07001058 getPhone(subId).updateServiceLocation();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001059 }
1060
1061 public boolean isRadioOn() {
Wink Saville36469e72014-06-11 15:17:00 -07001062 return isRadioOnUsingSubId(getDefaultSubscription());
1063 }
1064
1065 public boolean isRadioOnUsingSubId(long subId) {
1066 return getPhone(subId).getServiceState().getState() != ServiceState.STATE_POWER_OFF;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001067 }
1068
1069 public void toggleRadioOnOff() {
Wink Saville36469e72014-06-11 15:17:00 -07001070 toggleRadioOnOffUsingSubId(getDefaultSubscription());
1071
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001072 }
Wink Saville36469e72014-06-11 15:17:00 -07001073
1074 public void toggleRadioOnOffUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001075 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001076 getPhone(subId).setRadioPower(!isRadioOnUsingSubId(subId));
1077 }
1078
1079 public boolean setRadio(boolean turnOn) {
1080 return setRadioUsingSubId(getDefaultSubscription(), turnOn);
1081 }
1082
1083 public boolean setRadioUsingSubId(long subId, boolean turnOn) {
1084 enforceModifyPermission();
1085 if ((getPhone(subId).getServiceState().getState() !=
1086 ServiceState.STATE_POWER_OFF) != turnOn) {
1087 toggleRadioOnOffUsingSubId(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001088 }
1089 return true;
1090 }
Wink Saville36469e72014-06-11 15:17:00 -07001091
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001092 public boolean setRadioPower(boolean turnOn) {
Wink Saville36469e72014-06-11 15:17:00 -07001093 return setRadioPowerUsingSubId(getDefaultSubscription(), turnOn);
1094 }
1095
1096 public boolean setRadioPowerUsingSubId(long subId, boolean turnOn) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001097 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001098 getPhone(subId).setRadioPower(turnOn);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001099 return true;
1100 }
1101
Wink Saville36469e72014-06-11 15:17:00 -07001102 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001103 public boolean enableDataConnectivity() {
1104 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001105 long subId = SubscriptionManager.getDefaultDataSubId();
1106 getPhone(subId).setDataEnabled(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001107 return true;
1108 }
1109
Wink Saville36469e72014-06-11 15:17:00 -07001110 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001111 public boolean disableDataConnectivity() {
1112 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001113 long subId = SubscriptionManager.getDefaultDataSubId();
1114 getPhone(subId).setDataEnabled(false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001115 return true;
1116 }
1117
Wink Saville36469e72014-06-11 15:17:00 -07001118 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001119 public boolean isDataConnectivityPossible() {
Wink Saville36469e72014-06-11 15:17:00 -07001120 long subId = SubscriptionManager.getDefaultDataSubId();
1121 return getPhone(subId).isDataConnectivityPossible();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001122 }
1123
1124 public boolean handlePinMmi(String dialString) {
Wink Saville36469e72014-06-11 15:17:00 -07001125 return handlePinMmiUsingSubId(getDefaultSubscription(), dialString);
1126 }
1127
1128 public boolean handlePinMmiUsingSubId(long subId, String dialString) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001129 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001130 return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001131 }
1132
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001133 public int getCallState() {
Wink Saville36469e72014-06-11 15:17:00 -07001134 return getCallStateUsingSubId(getDefaultSubscription());
1135 }
1136
1137 public int getCallStateUsingSubId(long subId) {
1138 return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001139 }
1140
1141 public int getDataState() {
Wink Saville36469e72014-06-11 15:17:00 -07001142 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1143 return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001144 }
1145
1146 public int getDataActivity() {
Wink Saville36469e72014-06-11 15:17:00 -07001147 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1148 return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001149 }
1150
1151 @Override
1152 public Bundle getCellLocation() {
1153 try {
1154 mApp.enforceCallingOrSelfPermission(
1155 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1156 } catch (SecurityException e) {
1157 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1158 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1159 // is the weaker precondition
1160 mApp.enforceCallingOrSelfPermission(
1161 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1162 }
1163
Jake Hambye994d462014-02-03 13:10:13 -08001164 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001165 if (DBG_LOC) log("getCellLocation: is active user");
1166 Bundle data = new Bundle();
1167 mPhone.getCellLocation().fillInNotifierBundle(data);
1168 return data;
1169 } else {
1170 if (DBG_LOC) log("getCellLocation: suppress non-active user");
1171 return null;
1172 }
1173 }
1174
1175 @Override
1176 public void enableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001177 enableLocationUpdatesUsingSubId(getDefaultSubscription());
1178 }
1179
1180 public void enableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001181 mApp.enforceCallingOrSelfPermission(
1182 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001183 getPhone(subId).enableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001184 }
1185
1186 @Override
1187 public void disableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001188 disableLocationUpdatesUsingSubId(getDefaultSubscription());
1189 }
1190
1191 public void disableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001192 mApp.enforceCallingOrSelfPermission(
1193 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001194 getPhone(subId).disableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001195 }
1196
1197 @Override
1198 @SuppressWarnings("unchecked")
1199 public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1200 try {
1201 mApp.enforceCallingOrSelfPermission(
1202 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1203 } catch (SecurityException e) {
1204 // If we have ACCESS_FINE_LOCATION permission, skip the check
1205 // for ACCESS_COARSE_LOCATION
1206 // A failure should throw the SecurityException from
1207 // ACCESS_COARSE_LOCATION since this is the weaker precondition
1208 mApp.enforceCallingOrSelfPermission(
1209 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1210 }
1211
1212 if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1213 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1214 return null;
1215 }
Jake Hambye994d462014-02-03 13:10:13 -08001216 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001217 if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1218
1219 ArrayList<NeighboringCellInfo> cells = null;
1220
1221 try {
1222 cells = (ArrayList<NeighboringCellInfo>) sendRequest(
Wink Saville36469e72014-06-11 15:17:00 -07001223 CMD_HANDLE_NEIGHBORING_CELL, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001224 } catch (RuntimeException e) {
Wink Saville36469e72014-06-11 15:17:00 -07001225 Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001226 }
1227 return cells;
1228 } else {
1229 if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1230 return null;
1231 }
1232 }
1233
1234
1235 @Override
1236 public List<CellInfo> getAllCellInfo() {
1237 try {
1238 mApp.enforceCallingOrSelfPermission(
1239 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1240 } catch (SecurityException e) {
1241 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1242 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1243 // is the weaker precondition
1244 mApp.enforceCallingOrSelfPermission(
1245 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1246 }
1247
Jake Hambye994d462014-02-03 13:10:13 -08001248 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001249 if (DBG_LOC) log("getAllCellInfo: is active user");
1250 return mPhone.getAllCellInfo();
1251 } else {
1252 if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1253 return null;
1254 }
1255 }
1256
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -07001257 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001258 public void setCellInfoListRate(int rateInMillis) {
1259 mPhone.setCellInfoListRate(rateInMillis);
1260 }
1261
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001262 //
1263 // Internal helper methods.
1264 //
1265
Jake Hambye994d462014-02-03 13:10:13 -08001266 private static boolean checkIfCallerIsSelfOrForegroundUser() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001267 boolean ok;
1268
1269 boolean self = Binder.getCallingUid() == Process.myUid();
1270 if (!self) {
1271 // Get the caller's user id then clear the calling identity
1272 // which will be restored in the finally clause.
1273 int callingUser = UserHandle.getCallingUserId();
1274 long ident = Binder.clearCallingIdentity();
1275
1276 try {
1277 // With calling identity cleared the current user is the foreground user.
1278 int foregroundUser = ActivityManager.getCurrentUser();
1279 ok = (foregroundUser == callingUser);
1280 if (DBG_LOC) {
1281 log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1282 + " callingUser=" + callingUser + " ok=" + ok);
1283 }
1284 } catch (Exception ex) {
1285 if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1286 ok = false;
1287 } finally {
1288 Binder.restoreCallingIdentity(ident);
1289 }
1290 } else {
1291 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1292 ok = true;
1293 }
1294 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1295 return ok;
1296 }
1297
1298 /**
1299 * Make sure the caller has the READ_PHONE_STATE permission.
1300 *
1301 * @throws SecurityException if the caller does not have the required permission
1302 */
1303 private void enforceReadPermission() {
1304 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
1305 }
1306
1307 /**
1308 * Make sure the caller has the MODIFY_PHONE_STATE permission.
1309 *
1310 * @throws SecurityException if the caller does not have the required permission
1311 */
1312 private void enforceModifyPermission() {
1313 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1314 }
1315
1316 /**
Junda Liua2e36012014-07-09 18:30:01 -07001317 * Make sure either system app or the caller has carrier privilege.
1318 *
1319 * @throws SecurityException if the caller does not have the required permission/privilege
1320 */
1321 private void enforceModifyPermissionOrCarrierPrivilege() {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001322 int permission = mApp.checkCallingOrSelfPermission(
1323 android.Manifest.permission.MODIFY_PHONE_STATE);
1324 if (permission == PackageManager.PERMISSION_GRANTED) {
1325 return;
1326 }
1327
1328 log("No modify permission, check carrier privilege next.");
1329 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1330 loge("No Carrier Privilege.");
1331 throw new SecurityException("No modify permission or carrier privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001332 }
1333 }
1334
1335 /**
1336 * Make sure the caller has carrier privilege.
1337 *
1338 * @throws SecurityException if the caller does not have the required permission
1339 */
1340 private void enforceCarrierPrivilege() {
1341 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001342 loge("No Carrier Privilege.");
1343 throw new SecurityException("No Carrier Privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001344 }
1345 }
1346
1347 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001348 * Make sure the caller has the CALL_PHONE permission.
1349 *
1350 * @throws SecurityException if the caller does not have the required permission
1351 */
1352 private void enforceCallPermission() {
1353 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1354 }
1355
Shishir Agrawal566b7612013-10-28 14:41:00 -07001356 /**
Gabriel Peal36ebb0d2014-03-20 09:20:43 -07001357 * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1358 *
1359 * @throws SecurityException if the caller does not have the required permission
1360 */
1361 private void enforcePrivilegedPhoneStatePermission() {
1362 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1363 null);
1364 }
1365
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001366 private String createTelUrl(String number) {
1367 if (TextUtils.isEmpty(number)) {
1368 return null;
1369 }
1370
Jake Hambye994d462014-02-03 13:10:13 -08001371 return "tel:" + number;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001372 }
1373
Ihab Awadf9e92732013-12-05 18:02:52 -08001374 private static void log(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001375 Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1376 }
1377
Ihab Awadf9e92732013-12-05 18:02:52 -08001378 private static void loge(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001379 Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1380 }
1381
1382 public int getActivePhoneType() {
Wink Saville36469e72014-06-11 15:17:00 -07001383 return getActivePhoneTypeUsingSubId(getDefaultSubscription());
1384 }
1385
1386 public int getActivePhoneTypeUsingSubId(long subId) {
1387 return getPhone(subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001388 }
1389
1390 /**
1391 * Returns the CDMA ERI icon index to display
1392 */
1393 public int getCdmaEriIconIndex() {
Wink Saville36469e72014-06-11 15:17:00 -07001394 return getCdmaEriIconIndexUsingSubId(getDefaultSubscription());
1395
1396 }
1397
1398 public int getCdmaEriIconIndexUsingSubId(long subId) {
1399 return getPhone(subId).getCdmaEriIconIndex();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001400 }
1401
1402 /**
1403 * Returns the CDMA ERI icon mode,
1404 * 0 - ON
1405 * 1 - FLASHING
1406 */
1407 public int getCdmaEriIconMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001408 return getCdmaEriIconModeUsingSubId(getDefaultSubscription());
1409 }
1410
1411 public int getCdmaEriIconModeUsingSubId(long subId) {
1412 return getPhone(subId).getCdmaEriIconMode();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001413 }
1414
1415 /**
1416 * Returns the CDMA ERI text,
1417 */
1418 public String getCdmaEriText() {
Wink Saville36469e72014-06-11 15:17:00 -07001419 return getCdmaEriTextUsingSubId(getDefaultSubscription());
1420 }
1421
1422 public String getCdmaEriTextUsingSubId(long subId) {
1423 return getPhone(subId).getCdmaEriText();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001424 }
1425
1426 /**
1427 * Returns true if CDMA provisioning needs to run.
1428 */
1429 public boolean needsOtaServiceProvisioning() {
1430 return mPhone.needsOtaServiceProvisioning();
1431 }
1432
1433 /**
1434 * Returns the unread count of voicemails
1435 */
1436 public int getVoiceMessageCount() {
Wink Saville36469e72014-06-11 15:17:00 -07001437 return getVoiceMessageCountUsingSubId(getDefaultSubscription());
1438 }
1439
1440 /**
1441 * Returns the unread count of voicemails for a subId
1442 */
1443 public int getVoiceMessageCountUsingSubId( long subId) {
1444 return getPhone(subId).getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001445 }
1446
1447 /**
1448 * Returns the data network type
1449 *
1450 * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1451 */
1452 @Override
1453 public int getNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001454 return getNetworkTypeUsingSubId(getDefaultSubscription());
1455 }
1456
1457 /**
1458 * Returns the network type for a subId
1459 */
1460 @Override
1461 public int getNetworkTypeUsingSubId(long subId) {
1462 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001463 }
1464
1465 /**
1466 * Returns the data network type
1467 */
1468 @Override
1469 public int getDataNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001470 return getDataNetworkTypeUsingSubId(getDefaultSubscription());
1471 }
1472
1473 /**
1474 * Returns the data network type for a subId
1475 */
1476 @Override
1477 public int getDataNetworkTypeUsingSubId(long subId) {
1478 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001479 }
1480
1481 /**
1482 * Returns the data network type
1483 */
1484 @Override
1485 public int getVoiceNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001486 return getVoiceNetworkTypeUsingSubId(getDefaultSubscription());
1487 }
1488
1489 /**
1490 * Returns the Voice network type for a subId
1491 */
1492 @Override
1493 public int getVoiceNetworkTypeUsingSubId(long subId) {
1494 return getPhone(subId).getServiceState().getVoiceNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001495 }
1496
1497 /**
1498 * @return true if a ICC card is present
1499 */
1500 public boolean hasIccCard() {
Wink Saville36469e72014-06-11 15:17:00 -07001501 // FIXME Make changes to pass defaultSimId of type int
1502 return hasIccCardUsingSlotId(getDefaultSubscription());
1503 }
1504
1505 /**
1506 * @return true if a ICC card is present for a slotId
1507 */
1508 public boolean hasIccCardUsingSlotId(long slotId) {
1509 return getPhone(slotId).getIccCard().hasIccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001510 }
1511
1512 /**
1513 * Return if the current radio is LTE on CDMA. This
1514 * is a tri-state return value as for a period of time
1515 * the mode may be unknown.
1516 *
1517 * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
Jake Hambye994d462014-02-03 13:10:13 -08001518 * or {@link Phone#LTE_ON_CDMA_TRUE}
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001519 */
1520 public int getLteOnCdmaMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001521 return getLteOnCdmaModeUsingSubId(getDefaultSubscription());
1522 }
1523
1524 public int getLteOnCdmaModeUsingSubId(long subId) {
1525 return getPhone(subId).getLteOnCdmaMode();
1526 }
1527
1528 public void setPhone(Phone phone) {
1529 mPhone = phone;
1530 }
1531
1532 /**
1533 * {@hide}
1534 * Returns Default subId, 0 in the case of single standby.
1535 */
1536 private long getDefaultSubscription() {
1537 return SubscriptionManager.getDefaultSubId();
1538 }
1539
1540 private long getPreferredVoiceSubscription() {
1541 return SubscriptionManager.getDefaultVoiceSubId();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001542 }
Ihab Awadf2177b72013-11-25 13:33:23 -08001543
1544 /**
1545 * @see android.telephony.TelephonyManager.WifiCallingChoices
1546 */
1547 public int getWhenToMakeWifiCalls() {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001548 return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1549 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
Ihab Awadf2177b72013-11-25 13:33:23 -08001550 }
1551
1552 /**
1553 * @see android.telephony.TelephonyManager.WifiCallingChoices
1554 */
1555 public void setWhenToMakeWifiCalls(int preference) {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001556 if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1557 Settings.System.putInt(mPhone.getContext().getContentResolver(),
1558 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
Ihab Awadf9e92732013-12-05 18:02:52 -08001559 }
1560
Sailesh Nepald1e68152013-12-12 19:08:02 -08001561 private static int getWhenToMakeWifiCallsDefaultPreference() {
1562 // TODO(sail): Use a build property to choose this value.
Evan Charlton9829e882013-12-19 15:30:38 -08001563 return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
Ihab Awadf2177b72013-11-25 13:33:23 -08001564 }
Shishir Agrawal69f68122013-12-16 17:25:49 -08001565
Shishir Agrawal566b7612013-10-28 14:41:00 -07001566 @Override
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001567 public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID) {
Junda Liua2e36012014-07-09 18:30:01 -07001568 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001569
1570 if (DBG) log("iccOpenLogicalChannel: " + AID);
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001571 IccOpenLogicalChannelResponse response = (IccOpenLogicalChannelResponse)sendRequest(
1572 CMD_OPEN_CHANNEL, AID);
1573 if (DBG) log("iccOpenLogicalChannel: " + response);
1574 return response;
Shishir Agrawal566b7612013-10-28 14:41:00 -07001575 }
1576
1577 @Override
1578 public boolean iccCloseLogicalChannel(int channel) {
Junda Liua2e36012014-07-09 18:30:01 -07001579 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001580
1581 if (DBG) log("iccCloseLogicalChannel: " + channel);
1582 if (channel < 0) {
1583 return false;
1584 }
Jake Hambye994d462014-02-03 13:10:13 -08001585 Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
Shishir Agrawal566b7612013-10-28 14:41:00 -07001586 if (DBG) log("iccCloseLogicalChannel: " + success);
1587 return success;
1588 }
1589
1590 @Override
1591 public String iccTransmitApduLogicalChannel(int channel, int cla,
1592 int command, int p1, int p2, int p3, String data) {
Junda Liua2e36012014-07-09 18:30:01 -07001593 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001594
1595 if (DBG) {
1596 log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1597 " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1598 " data=" + data);
1599 }
1600
1601 if (channel < 0) {
1602 return "";
1603 }
1604
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001605 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_LOGICAL_CHANNEL,
Shishir Agrawal566b7612013-10-28 14:41:00 -07001606 new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1607 if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1608
1609 // If the payload is null, there was an error. Indicate that by returning
1610 // an empty string.
1611 if (response.payload == null) {
1612 return "";
1613 }
1614
1615 // Append the returned status code to the end of the response payload.
1616 String s = Integer.toHexString(
1617 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1618 s = IccUtils.bytesToHexString(response.payload) + s;
1619 return s;
1620 }
Jake Hambye994d462014-02-03 13:10:13 -08001621
Evan Charltonc66da362014-05-16 14:06:40 -07001622 @Override
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001623 public String iccTransmitApduBasicChannel(int cla, int command, int p1, int p2,
1624 int p3, String data) {
1625 enforceModifyPermissionOrCarrierPrivilege();
1626
1627 if (DBG) {
1628 log("iccTransmitApduBasicChannel: cla=" + cla + " cmd=" + command + " p1="
1629 + p1 + " p2=" + p2 + " p3=" + p3 + " data=" + data);
1630 }
1631
1632 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_BASIC_CHANNEL,
1633 new IccAPDUArgument(0, cla, command, p1, p2, p3, data));
1634 if (DBG) log("iccTransmitApduBasicChannel: " + response);
1635
1636 // If the payload is null, there was an error. Indicate that by returning
1637 // an empty string.
1638 if (response.payload == null) {
1639 return "";
1640 }
1641
1642 // Append the returned status code to the end of the response payload.
1643 String s = Integer.toHexString(
1644 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1645 s = IccUtils.bytesToHexString(response.payload) + s;
1646 return s;
1647 }
1648
1649 @Override
1650 public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
1651 String filePath) {
1652 enforceModifyPermissionOrCarrierPrivilege();
1653
1654 if (DBG) {
1655 log("Exchange SIM_IO " + fileID + ":" + command + " " +
1656 p1 + " " + p2 + " " + p3 + ":" + filePath);
1657 }
1658
1659 IccIoResult response =
1660 (IccIoResult)sendRequest(CMD_EXCHANGE_SIM_IO,
1661 new IccAPDUArgument(fileID, command, -1, p1, p2, p3, filePath));
1662
1663 if (DBG) {
1664 log("Exchange SIM_IO [R]" + response);
1665 }
1666
1667 byte[] result = null;
1668 int length = 2;
1669 if (response.payload != null) {
1670 length = 2 + response.payload.length;
1671 result = new byte[length];
1672 System.arraycopy(response.payload, 0, result, 0, response.payload.length);
1673 } else {
1674 result = new byte[length];
1675 }
1676
1677 result[length - 1] = (byte) response.sw2;
1678 result[length - 2] = (byte) response.sw1;
1679 return result;
1680 }
1681
1682 @Override
Evan Charltonc66da362014-05-16 14:06:40 -07001683 public String sendEnvelopeWithStatus(String content) {
Junda Liua2e36012014-07-09 18:30:01 -07001684 enforceModifyPermissionOrCarrierPrivilege();
Evan Charltonc66da362014-05-16 14:06:40 -07001685
1686 IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
1687 if (response.payload == null) {
1688 return "";
1689 }
1690
1691 // Append the returned status code to the end of the response payload.
1692 String s = Integer.toHexString(
1693 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1694 s = IccUtils.bytesToHexString(response.payload) + s;
1695 return s;
1696 }
1697
Jake Hambye994d462014-02-03 13:10:13 -08001698 /**
1699 * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1700 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1701 *
1702 * @param itemID the ID of the item to read
1703 * @return the NV item as a String, or null on error.
1704 */
1705 @Override
1706 public String nvReadItem(int itemID) {
Junda Liua2e36012014-07-09 18:30:01 -07001707 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001708 if (DBG) log("nvReadItem: item " + itemID);
1709 String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
1710 if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
1711 return value;
1712 }
1713
1714 /**
1715 * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1716 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1717 *
1718 * @param itemID the ID of the item to read
1719 * @param itemValue the value to write, as a String
1720 * @return true on success; false on any failure
1721 */
1722 @Override
1723 public boolean nvWriteItem(int itemID, String itemValue) {
Junda Liua2e36012014-07-09 18:30:01 -07001724 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001725 if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
1726 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
1727 new Pair<Integer, String>(itemID, itemValue));
1728 if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
1729 return success;
1730 }
1731
1732 /**
1733 * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
1734 * Used for device configuration by some CDMA operators.
1735 *
1736 * @param preferredRoamingList byte array containing the new PRL
1737 * @return true on success; false on any failure
1738 */
1739 @Override
1740 public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
Junda Liua2e36012014-07-09 18:30:01 -07001741 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001742 if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
1743 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
1744 if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
1745 return success;
1746 }
1747
1748 /**
1749 * Perform the specified type of NV config reset.
1750 * Used for device configuration by some CDMA operators.
1751 *
1752 * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
1753 * @return true on success; false on any failure
1754 */
1755 @Override
1756 public boolean nvResetConfig(int resetType) {
Junda Liua2e36012014-07-09 18:30:01 -07001757 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001758 if (DBG) log("nvResetConfig: type " + resetType);
1759 Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
1760 if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
1761 return success;
1762 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001763
1764 /**
Wink Saville36469e72014-06-11 15:17:00 -07001765 * {@hide}
1766 * Returns Default sim, 0 in the case of single standby.
1767 */
1768 public int getDefaultSim() {
1769 //TODO Need to get it from Telephony Devcontroller
1770 return 0;
1771 }
1772
ram87fca6f2014-07-18 18:58:44 +05301773 public String[] getPcscfAddress(String apnType) {
Wink Saville36469e72014-06-11 15:17:00 -07001774 enforceReadPermission();
ram87fca6f2014-07-18 18:58:44 +05301775 return mPhone.getPcscfAddress(apnType);
Wink Saville36469e72014-06-11 15:17:00 -07001776 }
1777
1778 public void setImsRegistrationState(boolean registered) {
1779 enforceModifyPermission();
1780 mPhone.setImsRegistrationState(registered);
1781 }
1782
1783 /**
Junda Liu84d15a22014-07-02 11:21:04 -07001784 * Get the calculated preferred network type.
1785 * Used for debugging incorrect network type.
1786 *
1787 * @return the preferred network type, defined in RILConstants.java.
1788 */
1789 @Override
1790 public int getCalculatedPreferredNetworkType() {
1791 enforceReadPermission();
1792 return PhoneFactory.calculatePreferredNetworkType(mPhone.getContext());
1793 }
1794
1795 /**
Jake Hamby7c27be32014-03-03 13:25:59 -08001796 * Get the preferred network type.
1797 * Used for device configuration by some CDMA operators.
1798 *
1799 * @return the preferred network type, defined in RILConstants.java.
1800 */
1801 @Override
1802 public int getPreferredNetworkType() {
Junda Liua2e36012014-07-09 18:30:01 -07001803 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001804 if (DBG) log("getPreferredNetworkType");
1805 int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null);
1806 int networkType = (result != null ? result[0] : -1);
1807 if (DBG) log("getPreferredNetworkType: " + networkType);
1808 return networkType;
1809 }
1810
1811 /**
1812 * Set the preferred network type.
1813 * Used for device configuration by some CDMA operators.
1814 *
1815 * @param networkType the preferred network type, defined in RILConstants.java.
1816 * @return true on success; false on any failure.
1817 */
1818 @Override
1819 public boolean setPreferredNetworkType(int networkType) {
Junda Liua2e36012014-07-09 18:30:01 -07001820 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001821 if (DBG) log("setPreferredNetworkType: type " + networkType);
1822 Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType);
1823 if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
Junda Liu80bc0d12014-07-14 16:36:44 -07001824 if (success) {
1825 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1826 Settings.Global.PREFERRED_NETWORK_MODE, networkType);
1827 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001828 return success;
1829 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001830
1831 /**
Junda Liu787bc7e2014-06-30 13:38:02 -07001832 * Set the CDMA subscription source.
1833 * Used for device supporting both NV and RUIM for CDMA.
1834 *
1835 * @param subscriptionType the subscription type, 0 for RUIM, 1 for NV.
1836 * @return true on success; false on any failure.
1837 */
1838 @Override
1839 public boolean setCdmaSubscription(int subscriptionType) {
Junda Liua2e36012014-07-09 18:30:01 -07001840 enforceModifyPermissionOrCarrierPrivilege();
Junda Liu787bc7e2014-06-30 13:38:02 -07001841 if (DBG) log("setCdmaSubscription: type " + subscriptionType);
1842 if (subscriptionType != mPhone.CDMA_SUBSCRIPTION_RUIM_SIM &&
1843 subscriptionType != mPhone.CDMA_SUBSCRIPTION_NV) {
1844 loge("setCdmaSubscription: unsupported subscriptionType.");
1845 return false;
1846 }
1847 Boolean success = (Boolean) sendRequest(CMD_SET_CDMA_SUBSCRIPTION, subscriptionType);
1848 if (DBG) log("setCdmaSubscription: " + (success ? "ok" : "fail"));
1849 if (success) {
1850 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1851 Settings.Global.CDMA_SUBSCRIPTION_MODE, subscriptionType);
1852 }
1853 return success;
1854 }
1855
1856 /**
Robert Greenwalted86e582014-05-21 20:03:20 -07001857 * Set mobile data enabled
1858 * Used by the user through settings etc to turn on/off mobile data
1859 *
1860 * @param enable {@code true} turn turn data on, else {@code false}
1861 */
1862 @Override
1863 public void setDataEnabled(boolean enable) {
1864 enforceModifyPermission();
1865 mPhone.setDataEnabled(enable);
1866 }
1867
1868 /**
Robert Greenwalt646120a2014-05-23 11:54:03 -07001869 * Get whether mobile data is enabled.
1870 *
1871 * Note that this used to be available from ConnectivityService, gated by
1872 * ACCESS_NETWORK_STATE permission, so this will accept either that or
1873 * our MODIFY_PHONE_STATE.
Robert Greenwalted86e582014-05-21 20:03:20 -07001874 *
1875 * @return {@code true} if data is enabled else {@code false}
1876 */
1877 @Override
1878 public boolean getDataEnabled() {
Robert Greenwalt646120a2014-05-23 11:54:03 -07001879 try {
1880 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
1881 null);
1882 } catch (Exception e) {
1883 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
1884 null);
1885 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001886 return mPhone.getDataEnabled();
1887 }
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001888
1889 @Override
1890 public int hasCarrierPrivileges() {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001891 UiccCard card = UiccController.getInstance().getUiccCard();
1892 if (card == null) {
1893 loge("hasCarrierPrivileges: No UICC");
1894 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1895 }
1896 return card.getCarrierPrivilegeStatusForCurrentTransaction(
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001897 mPhone.getContext().getPackageManager());
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001898 }
Junda Liu29340342014-07-10 15:23:27 -07001899
1900 @Override
Shishir Agrawal6d5a2852014-07-11 16:32:57 -07001901 public int checkCarrierPrivilegesForPackage(String pkgname) {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001902 UiccCard card = UiccController.getInstance().getUiccCard();
1903 if (card == null) {
1904 loge("checkCarrierPrivilegesForPackage: No UICC");
1905 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1906 }
1907 return card.getCarrierPrivilegeStatus(mPhone.getContext().getPackageManager(), pkgname);
Junda Liu29340342014-07-10 15:23:27 -07001908 }
Derek Tan89e89d42014-07-08 17:00:10 -07001909
1910 @Override
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001911 public List<String> getCarrierPackageNamesForBroadcastIntent(Intent intent) {
1912 UiccCard card = UiccController.getInstance().getUiccCard();
1913 if (card == null) {
1914 loge("getCarrierPackageNamesForBroadcastIntent: No UICC");
1915 return null ;
1916 }
1917 return card.getCarrierPackageNamesForBroadcastIntent(
1918 mPhone.getContext().getPackageManager(), intent);
1919 }
1920
1921 @Override
Derek Tan89e89d42014-07-08 17:00:10 -07001922 public void enableSimplifiedNetworkSettings(long subId, boolean enable) {
Derek Tan352d8cd2014-07-12 12:57:11 -07001923 enforceModifyPermissionOrCarrierPrivilege();
Derek Tan89e89d42014-07-08 17:00:10 -07001924 if (enable) {
1925 mSimplifiedNetworkSettings.add(subId);
1926 } else {
1927 mSimplifiedNetworkSettings.remove(subId);
1928 }
1929 }
1930
1931 @Override
1932 public boolean getSimplifiedNetworkSettingsEnabled(long subId) {
1933 enforceReadPermission();
1934 return mSimplifiedNetworkSettings.contains(subId);
1935 }
Derek Tan7226c842014-07-02 17:42:23 -07001936
1937 @Override
1938 public void setLine1NumberForDisplay(long subId, String alphaTag, String number) {
Derek Tan352d8cd2014-07-12 12:57:11 -07001939 enforceModifyPermissionOrCarrierPrivilege();
Derek Tan7226c842014-07-02 17:42:23 -07001940 mAdnRecordsForDisplay.put(subId, new AdnRecord(alphaTag, number));
1941 }
1942
1943 @Override
1944 public String getLine1NumberForDisplay(long subId) {
1945 enforceReadPermission();
1946 if (!mAdnRecordsForDisplay.containsKey(subId)) {
1947 return null;
1948 }
1949 AdnRecord adnRecord = mAdnRecordsForDisplay.get(subId);
1950 if (adnRecord.getNumber() == null || adnRecord.getNumber().isEmpty()) {
1951 return null;
1952 }
1953 return adnRecord.getNumber();
1954 }
1955
1956 @Override
1957 public String getLine1AlphaTagForDisplay(long subId) {
1958 enforceReadPermission();
1959 if (!mAdnRecordsForDisplay.containsKey(subId)) {
1960 return null;
1961 }
1962 AdnRecord adnRecord = mAdnRecordsForDisplay.get(subId);
1963 if (adnRecord.getAlphaTag() == null || adnRecord.getAlphaTag().isEmpty()) {
1964 return null;
1965 }
1966 return adnRecord.getAlphaTag();
1967 }
Shishir Agrawalb1ebf8c2014-07-17 16:32:41 -07001968
1969 @Override
1970 public boolean setOperatorBrandOverride(String iccId, String brand) {
1971 enforceModifyPermissionOrCarrierPrivilege();
1972 return mPhone.setOperatorBrandOverride(iccId, brand);
1973 }
Steven Liu4bf01bc2014-07-17 11:05:29 -05001974
1975 @Override
1976 public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
1977 enforceModifyPermission();
1978
1979 int returnValue = 0;
1980 try {
1981 AsyncResult result = (AsyncResult)sendRequest(CMD_INVOKE_OEM_RIL_REQUEST_RAW, oemReq);
1982 if(result.exception == null) {
1983 if (result.result != null) {
1984 byte[] responseData = (byte[])(result.result);
1985 if(responseData.length > oemResp.length) {
1986 Log.w(LOG_TAG, "Buffer to copy response too small: Response length is " +
1987 responseData.length + "bytes. Buffer Size is " +
1988 oemResp.length + "bytes.");
1989 }
1990 System.arraycopy(responseData, 0, oemResp, 0, responseData.length);
1991 returnValue = responseData.length;
1992 }
1993 } else {
1994 CommandException ex = (CommandException) result.exception;
1995 returnValue = ex.getCommandError().ordinal();
1996 if(returnValue > 0) returnValue *= -1;
1997 }
1998 } catch (RuntimeException e) {
1999 Log.w(LOG_TAG, "sendOemRilRequestRaw: Runtime Exception");
2000 returnValue = (CommandException.Error.GENERIC_FAILURE.ordinal());
2001 if(returnValue > 0) returnValue *= -1;
2002 }
2003
2004 return returnValue;
2005 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07002006}