blob: b261aa13b65f3fbbde1ef24852e61f80cecca842 [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;
Derek Tan97ebb422014-09-05 16:55:38 -070024import android.content.SharedPreferences;
Shishir Agrawal60f9c952014-06-23 12:00:43 -070025import android.content.pm.PackageInfo;
26import android.content.pm.PackageManager;
27import android.content.pm.Signature;
Wink Saville36469e72014-06-11 15:17:00 -070028import android.net.ConnectivityManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070029import android.net.Uri;
30import android.os.AsyncResult;
31import android.os.Binder;
32import android.os.Bundle;
33import android.os.Handler;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070034import android.os.IBinder;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070035import android.os.Looper;
36import android.os.Message;
37import android.os.Process;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070038import android.os.RemoteException;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070039import android.os.ServiceManager;
40import android.os.UserHandle;
Derek Tan97ebb422014-09-05 16:55:38 -070041import android.preference.PreferenceManager;
Ihab Awadf2177b72013-11-25 13:33:23 -080042import android.provider.Settings;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070043import android.telephony.CellInfo;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -070044import android.telephony.IccOpenLogicalChannelResponse;
Jake Hambye994d462014-02-03 13:10:13 -080045import android.telephony.NeighboringCellInfo;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070046import android.telephony.ServiceState;
Wink Saville36469e72014-06-11 15:17:00 -070047import android.telephony.SubscriptionManager;
Ihab Awadf2177b72013-11-25 13:33:23 -080048import android.telephony.TelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070049import android.text.TextUtils;
50import android.util.Log;
Jake Hambye994d462014-02-03 13:10:13 -080051import android.util.Pair;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070052
Shishir Agrawal566b7612013-10-28 14:41:00 -070053import com.android.internal.telephony.CallManager;
54import com.android.internal.telephony.CommandException;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070055import com.android.internal.telephony.Connection;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070056import com.android.internal.telephony.DefaultPhoneNotifier;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070057import com.android.internal.telephony.ITelephony;
Jake Hambye994d462014-02-03 13:10:13 -080058import com.android.internal.telephony.IccCard;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070059import com.android.internal.telephony.Phone;
Wink Saville36469e72014-06-11 15:17:00 -070060import com.android.internal.telephony.PhoneFactory;
61import com.android.internal.telephony.CallManager;
62import com.android.internal.telephony.CommandException;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070063import com.android.internal.telephony.PhoneConstants;
Wink Saville36469e72014-06-11 15:17:00 -070064import com.android.internal.telephony.dataconnection.DctController;
Derek Tan7226c842014-07-02 17:42:23 -070065import com.android.internal.telephony.uicc.AdnRecord;
Shishir Agrawal566b7612013-10-28 14:41:00 -070066import com.android.internal.telephony.uicc.IccIoResult;
67import com.android.internal.telephony.uicc.IccUtils;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -070068import com.android.internal.telephony.uicc.UiccCard;
Shishir Agrawal60f9c952014-06-23 12:00:43 -070069import com.android.internal.telephony.uicc.UiccCarrierPrivilegeRules;
Shishir Agrawal566b7612013-10-28 14:41:00 -070070import com.android.internal.telephony.uicc.UiccController;
Jake Hambye994d462014-02-03 13:10:13 -080071import com.android.internal.util.HexDump;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070072
Wink Saville36469e72014-06-11 15:17:00 -070073import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
74
Santos Cordon7d4ddf62013-07-10 11:58:08 -070075import java.util.ArrayList;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070076import java.util.HashMap;
Derek Tan89e89d42014-07-08 17:00:10 -070077import java.util.HashSet;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070078import java.util.Iterator;
Jake Hambye994d462014-02-03 13:10:13 -080079import java.util.List;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070080import java.util.Map;
Derek Tan89e89d42014-07-08 17:00:10 -070081import java.util.Set;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070082
83/**
84 * Implementation of the ITelephony interface.
85 */
Santos Cordon117fee72014-05-16 17:56:12 -070086public class PhoneInterfaceManager extends ITelephony.Stub {
Santos Cordon7d4ddf62013-07-10 11:58:08 -070087 private static final String LOG_TAG = "PhoneInterfaceManager";
88 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
89 private static final boolean DBG_LOC = false;
90
91 // Message codes used with mMainThreadHandler
92 private static final int CMD_HANDLE_PIN_MMI = 1;
93 private static final int CMD_HANDLE_NEIGHBORING_CELL = 2;
94 private static final int EVENT_NEIGHBORING_CELL_DONE = 3;
95 private static final int CMD_ANSWER_RINGING_CALL = 4;
96 private static final int CMD_END_CALL = 5; // not used yet
97 private static final int CMD_SILENCE_RINGER = 6;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -070098 private static final int CMD_TRANSMIT_APDU_LOGICAL_CHANNEL = 7;
99 private static final int EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE = 8;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700100 private static final int CMD_OPEN_CHANNEL = 9;
101 private static final int EVENT_OPEN_CHANNEL_DONE = 10;
102 private static final int CMD_CLOSE_CHANNEL = 11;
103 private static final int EVENT_CLOSE_CHANNEL_DONE = 12;
Jake Hambye994d462014-02-03 13:10:13 -0800104 private static final int CMD_NV_READ_ITEM = 13;
105 private static final int EVENT_NV_READ_ITEM_DONE = 14;
106 private static final int CMD_NV_WRITE_ITEM = 15;
107 private static final int EVENT_NV_WRITE_ITEM_DONE = 16;
108 private static final int CMD_NV_WRITE_CDMA_PRL = 17;
109 private static final int EVENT_NV_WRITE_CDMA_PRL_DONE = 18;
110 private static final int CMD_NV_RESET_CONFIG = 19;
111 private static final int EVENT_NV_RESET_CONFIG_DONE = 20;
Jake Hamby7c27be32014-03-03 13:25:59 -0800112 private static final int CMD_GET_PREFERRED_NETWORK_TYPE = 21;
113 private static final int EVENT_GET_PREFERRED_NETWORK_TYPE_DONE = 22;
114 private static final int CMD_SET_PREFERRED_NETWORK_TYPE = 23;
115 private static final int EVENT_SET_PREFERRED_NETWORK_TYPE_DONE = 24;
Sailesh Nepal35b59452014-03-06 09:26:56 -0800116 private static final int CMD_SEND_ENVELOPE = 25;
117 private static final int EVENT_SEND_ENVELOPE_DONE = 26;
Derek Tan6b088ee2014-09-05 14:15:18 -0700118 private static final int CMD_INVOKE_OEM_RIL_REQUEST_RAW = 27;
119 private static final int EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE = 28;
120 private static final int CMD_TRANSMIT_APDU_BASIC_CHANNEL = 29;
121 private static final int EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE = 30;
122 private static final int CMD_EXCHANGE_SIM_IO = 31;
123 private static final int EVENT_EXCHANGE_SIM_IO_DONE = 32;
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
Derek Tan97ebb422014-09-05 16:55:38 -0700134 SharedPreferences carrierPrivilegeConfigs;
135 private static final String PREF_CARRIERS_ALPHATAG_PREFIX = "carrier_alphtag_";
136 private static final String PREF_CARRIERS_NUMBER_PREFIX = "carrier_number_";
137 private static final String PREF_CARRIERS_SIMPLIFIED_NETWORK_SETTINGS_PREFIX =
138 "carrier_simplified_network_settings_";
Derek Tan89e89d42014-07-08 17:00:10 -0700139
140 /**
Shishir Agrawal566b7612013-10-28 14:41:00 -0700141 * A request object to use for transmitting data to an ICC.
142 */
143 private static final class IccAPDUArgument {
144 public int channel, cla, command, p1, p2, p3;
145 public String data;
146
147 public IccAPDUArgument(int channel, int cla, int command,
148 int p1, int p2, int p3, String data) {
149 this.channel = channel;
150 this.cla = cla;
151 this.command = command;
152 this.p1 = p1;
153 this.p2 = p2;
154 this.p3 = p3;
155 this.data = data;
156 }
157 }
158
159 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700160 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
161 * request after sending. The main thread will notify the request when it is complete.
162 */
163 private static final class MainThreadRequest {
164 /** The argument to use for the request */
165 public Object argument;
166 /** The result of the request that is run on the main thread */
167 public Object result;
168
169 public MainThreadRequest(Object argument) {
170 this.argument = argument;
171 }
172 }
173
Sailesh Nepalcc0375f2013-11-13 09:15:18 -0800174 private static final class IncomingThirdPartyCallArgs {
175 public final ComponentName component;
176 public final String callId;
177 public final String callerDisplayName;
178
179 public IncomingThirdPartyCallArgs(ComponentName component, String callId,
180 String callerDisplayName) {
181 this.component = component;
182 this.callId = callId;
183 this.callerDisplayName = callerDisplayName;
184 }
185 }
186
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700187 /**
188 * A handler that processes messages on the main thread in the phone process. Since many
189 * of the Phone calls are not thread safe this is needed to shuttle the requests from the
190 * inbound binder threads to the main thread in the phone process. The Binder thread
191 * may provide a {@link MainThreadRequest} object in the msg.obj field that they are waiting
192 * on, which will be notified when the operation completes and will contain the result of the
193 * request.
194 *
195 * <p>If a MainThreadRequest object is provided in the msg.obj field,
196 * note that request.result must be set to something non-null for the calling thread to
197 * unblock.
198 */
199 private final class MainThreadHandler extends Handler {
200 @Override
201 public void handleMessage(Message msg) {
202 MainThreadRequest request;
203 Message onCompleted;
204 AsyncResult ar;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700205 UiccCard uiccCard = UiccController.getInstance().getUiccCard();
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700206 IccAPDUArgument iccArgument;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700207
208 switch (msg.what) {
209 case CMD_HANDLE_PIN_MMI:
210 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800211 request.result = mPhone.handlePinMmi((String) request.argument);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700212 // Wake up the requesting thread
213 synchronized (request) {
214 request.notifyAll();
215 }
216 break;
217
218 case CMD_HANDLE_NEIGHBORING_CELL:
219 request = (MainThreadRequest) msg.obj;
220 onCompleted = obtainMessage(EVENT_NEIGHBORING_CELL_DONE,
221 request);
222 mPhone.getNeighboringCids(onCompleted);
223 break;
224
225 case EVENT_NEIGHBORING_CELL_DONE:
226 ar = (AsyncResult) msg.obj;
227 request = (MainThreadRequest) ar.userObj;
228 if (ar.exception == null && ar.result != null) {
229 request.result = ar.result;
230 } else {
231 // create an empty list to notify the waiting thread
Jake Hambye994d462014-02-03 13:10:13 -0800232 request.result = new ArrayList<NeighboringCellInfo>(0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700233 }
234 // Wake up the requesting thread
235 synchronized (request) {
236 request.notifyAll();
237 }
238 break;
239
240 case CMD_ANSWER_RINGING_CALL:
241 answerRingingCallInternal();
242 break;
243
244 case CMD_SILENCE_RINGER:
245 silenceRingerInternal();
246 break;
247
248 case CMD_END_CALL:
249 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800250 boolean hungUp;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700251 int phoneType = mPhone.getPhoneType();
252 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
253 // CDMA: If the user presses the Power button we treat it as
254 // ending the complete call session
255 hungUp = PhoneUtils.hangupRingingAndActive(mPhone);
256 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
257 // GSM: End the call as per the Phone state
258 hungUp = PhoneUtils.hangup(mCM);
259 } else {
260 throw new IllegalStateException("Unexpected phone type: " + phoneType);
261 }
262 if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up"));
263 request.result = hungUp;
264 // Wake up the requesting thread
265 synchronized (request) {
266 request.notifyAll();
267 }
268 break;
269
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700270 case CMD_TRANSMIT_APDU_LOGICAL_CHANNEL:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700271 request = (MainThreadRequest) msg.obj;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700272 iccArgument = (IccAPDUArgument) request.argument;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700273 if (uiccCard == null) {
274 loge("iccTransmitApduLogicalChannel: No UICC");
275 request.result = new IccIoResult(0x6F, 0, (byte[])null);
276 synchronized (request) {
277 request.notifyAll();
278 }
279 } else {
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700280 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE,
281 request);
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700282 uiccCard.iccTransmitApduLogicalChannel(
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700283 iccArgument.channel, iccArgument.cla, iccArgument.command,
284 iccArgument.p1, iccArgument.p2, iccArgument.p3, iccArgument.data,
Shishir Agrawal566b7612013-10-28 14:41:00 -0700285 onCompleted);
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700286 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700287 break;
288
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700289 case EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700290 ar = (AsyncResult) msg.obj;
291 request = (MainThreadRequest) ar.userObj;
292 if (ar.exception == null && ar.result != null) {
293 request.result = ar.result;
294 } else {
295 request.result = new IccIoResult(0x6F, 0, (byte[])null);
296 if (ar.result == null) {
297 loge("iccTransmitApduLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800298 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700299 loge("iccTransmitApduLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800300 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700301 } else {
302 loge("iccTransmitApduLogicalChannel: Unknown exception");
303 }
304 }
305 synchronized (request) {
306 request.notifyAll();
307 }
308 break;
309
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700310 case CMD_TRANSMIT_APDU_BASIC_CHANNEL:
311 request = (MainThreadRequest) msg.obj;
312 iccArgument = (IccAPDUArgument) request.argument;
313 if (uiccCard == null) {
314 loge("iccTransmitApduBasicChannel: No UICC");
315 request.result = new IccIoResult(0x6F, 0, (byte[])null);
316 synchronized (request) {
317 request.notifyAll();
318 }
319 } else {
320 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE,
321 request);
322 uiccCard.iccTransmitApduBasicChannel(
323 iccArgument.cla, iccArgument.command, iccArgument.p1, iccArgument.p2,
324 iccArgument.p3, iccArgument.data, onCompleted);
325 }
326 break;
327
328 case EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE:
329 ar = (AsyncResult) msg.obj;
330 request = (MainThreadRequest) ar.userObj;
331 if (ar.exception == null && ar.result != null) {
332 request.result = ar.result;
333 } else {
334 request.result = new IccIoResult(0x6F, 0, (byte[])null);
335 if (ar.result == null) {
336 loge("iccTransmitApduBasicChannel: Empty response");
337 } else if (ar.exception instanceof CommandException) {
338 loge("iccTransmitApduBasicChannel: CommandException: " +
339 ar.exception);
340 } else {
341 loge("iccTransmitApduBasicChannel: Unknown exception");
342 }
343 }
344 synchronized (request) {
345 request.notifyAll();
346 }
347 break;
348
349 case CMD_EXCHANGE_SIM_IO:
350 request = (MainThreadRequest) msg.obj;
351 iccArgument = (IccAPDUArgument) request.argument;
352 if (uiccCard == null) {
353 loge("iccExchangeSimIO: No UICC");
354 request.result = new IccIoResult(0x6F, 0, (byte[])null);
355 synchronized (request) {
356 request.notifyAll();
357 }
358 } else {
359 onCompleted = obtainMessage(EVENT_EXCHANGE_SIM_IO_DONE,
360 request);
361 uiccCard.iccExchangeSimIO(iccArgument.cla, /* fileID */
362 iccArgument.command, iccArgument.p1, iccArgument.p2, iccArgument.p3,
363 iccArgument.data, onCompleted);
364 }
365 break;
366
367 case EVENT_EXCHANGE_SIM_IO_DONE:
368 ar = (AsyncResult) msg.obj;
369 request = (MainThreadRequest) ar.userObj;
370 if (ar.exception == null && ar.result != null) {
371 request.result = ar.result;
372 } else {
373 request.result = new IccIoResult(0x6f, 0, (byte[])null);
374 }
375 synchronized (request) {
376 request.notifyAll();
377 }
378 break;
379
Derek Tan4d5e5c12014-02-04 11:54:58 -0800380 case CMD_SEND_ENVELOPE:
381 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700382 if (uiccCard == null) {
383 loge("sendEnvelopeWithStatus: No UICC");
384 request.result = new IccIoResult(0x6F, 0, (byte[])null);
385 synchronized (request) {
386 request.notifyAll();
387 }
388 } else {
389 onCompleted = obtainMessage(EVENT_SEND_ENVELOPE_DONE, request);
390 uiccCard.sendEnvelopeWithStatus((String)request.argument, onCompleted);
391 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800392 break;
393
394 case EVENT_SEND_ENVELOPE_DONE:
395 ar = (AsyncResult) msg.obj;
396 request = (MainThreadRequest) ar.userObj;
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700397 if (ar.exception == null && ar.result != null) {
398 request.result = ar.result;
Derek Tan4d5e5c12014-02-04 11:54:58 -0800399 } else {
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700400 request.result = new IccIoResult(0x6F, 0, (byte[])null);
401 if (ar.result == null) {
402 loge("sendEnvelopeWithStatus: Empty response");
403 } else if (ar.exception instanceof CommandException) {
404 loge("sendEnvelopeWithStatus: CommandException: " +
405 ar.exception);
406 } else {
407 loge("sendEnvelopeWithStatus: exception:" + ar.exception);
408 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800409 }
410 synchronized (request) {
411 request.notifyAll();
412 }
413 break;
414
Shishir Agrawal566b7612013-10-28 14:41:00 -0700415 case CMD_OPEN_CHANNEL:
416 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700417 if (uiccCard == null) {
418 loge("iccOpenLogicalChannel: No UICC");
419 request.result = new IccIoResult(0x6F, 0, (byte[])null);
420 synchronized (request) {
421 request.notifyAll();
422 }
423 } else {
424 onCompleted = obtainMessage(EVENT_OPEN_CHANNEL_DONE, request);
425 uiccCard.iccOpenLogicalChannel((String)request.argument, onCompleted);
426 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700427 break;
428
429 case EVENT_OPEN_CHANNEL_DONE:
430 ar = (AsyncResult) msg.obj;
431 request = (MainThreadRequest) ar.userObj;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700432 IccOpenLogicalChannelResponse openChannelResp;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700433 if (ar.exception == null && ar.result != null) {
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700434 int[] result = (int[]) ar.result;
435 int channelId = result[0];
436 byte[] selectResponse = null;
437 if (result.length > 1) {
438 selectResponse = new byte[result.length - 1];
439 for (int i = 1; i < result.length; ++i) {
440 selectResponse[i - 1] = (byte) result[i];
441 }
442 }
443 openChannelResp = new IccOpenLogicalChannelResponse(channelId,
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700444 IccOpenLogicalChannelResponse.STATUS_NO_ERROR, selectResponse);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700445 } else {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700446 if (ar.result == null) {
447 loge("iccOpenLogicalChannel: Empty response");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700448 }
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700449 if (ar.exception != null) {
450 loge("iccOpenLogicalChannel: Exception: " + ar.exception);
451 }
452
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700453 int errorCode = IccOpenLogicalChannelResponse.STATUS_UNKNOWN_ERROR;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700454 if ((ar.exception != null) && (ar.exception instanceof CommandException)) {
455 if (ar.exception.getMessage().compareTo("MISSING_RESOURCE") == 0) {
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700456 errorCode = IccOpenLogicalChannelResponse.STATUS_MISSING_RESOURCE;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700457 } else if (ar.exception.getMessage().compareTo("NO_SUCH_ELEMENT") == 0) {
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700458 errorCode = IccOpenLogicalChannelResponse.STATUS_NO_SUCH_ELEMENT;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700459 }
460 }
461 openChannelResp = new IccOpenLogicalChannelResponse(
462 IccOpenLogicalChannelResponse.INVALID_CHANNEL, errorCode, null);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700463 }
Shishir Agrawal82c8a462014-07-31 18:13:17 -0700464 request.result = openChannelResp;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700465 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
Steven Liu4bf01bc2014-07-17 11:05:29 -0500584 case CMD_INVOKE_OEM_RIL_REQUEST_RAW:
585 request = (MainThreadRequest)msg.obj;
586 onCompleted = obtainMessage(EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE, request);
587 mPhone.invokeOemRilRequestRaw((byte[])request.argument, onCompleted);
588 break;
589
590 case EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE:
591 ar = (AsyncResult)msg.obj;
592 request = (MainThreadRequest)ar.userObj;
593 request.result = ar;
594 synchronized (request) {
595 request.notifyAll();
596 }
597 break;
598
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700599 default:
600 Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
601 break;
602 }
603 }
Jake Hambye994d462014-02-03 13:10:13 -0800604
605 private void handleNullReturnEvent(Message msg, String command) {
606 AsyncResult ar = (AsyncResult) msg.obj;
607 MainThreadRequest request = (MainThreadRequest) ar.userObj;
608 if (ar.exception == null) {
609 request.result = true;
610 } else {
611 request.result = false;
612 if (ar.exception instanceof CommandException) {
613 loge(command + ": CommandException: " + ar.exception);
614 } else {
615 loge(command + ": Unknown exception");
616 }
617 }
618 synchronized (request) {
619 request.notifyAll();
620 }
621 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700622 }
623
624 /**
625 * Posts the specified command to be executed on the main thread,
626 * waits for the request to complete, and returns the result.
627 * @see #sendRequestAsync
628 */
629 private Object sendRequest(int command, Object argument) {
Santos Cordon500b0e02014-06-17 10:33:33 -0700630 return sendRequest(command, argument, null);
Wink Saville36469e72014-06-11 15:17:00 -0700631 }
632
633 /**
634 * Posts the specified command to be executed on the main thread,
635 * waits for the request to complete, and returns the result.
636 * @see #sendRequestAsync
637 */
638 private Object sendRequest(int command, Object argument, Object argument2) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700639 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
640 throw new RuntimeException("This method will deadlock if called from the main thread.");
641 }
642
643 MainThreadRequest request = new MainThreadRequest(argument);
644 Message msg = mMainThreadHandler.obtainMessage(command, request);
645 msg.sendToTarget();
646
647 // Wait for the request to complete
648 synchronized (request) {
649 while (request.result == null) {
650 try {
651 request.wait();
652 } catch (InterruptedException e) {
653 // Do nothing, go back and wait until the request is complete
654 }
655 }
656 }
657 return request.result;
658 }
659
660 /**
661 * Asynchronous ("fire and forget") version of sendRequest():
662 * Posts the specified command to be executed on the main thread, and
663 * returns immediately.
664 * @see #sendRequest
665 */
666 private void sendRequestAsync(int command) {
667 mMainThreadHandler.sendEmptyMessage(command);
668 }
669
670 /**
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -0700671 * Same as {@link #sendRequestAsync(int)} except it takes an argument.
672 * @see {@link #sendRequest(int,Object)}
673 */
674 private void sendRequestAsync(int command, Object argument) {
675 MainThreadRequest request = new MainThreadRequest(argument);
676 Message msg = mMainThreadHandler.obtainMessage(command, request);
677 msg.sendToTarget();
678 }
679
680 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700681 * Initialize the singleton PhoneInterfaceManager instance.
682 * This is only done once, at startup, from PhoneApp.onCreate().
683 */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700684 /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700685 synchronized (PhoneInterfaceManager.class) {
686 if (sInstance == null) {
Sailesh Nepal194161e2014-07-03 08:57:44 -0700687 sInstance = new PhoneInterfaceManager(app, phone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700688 } else {
689 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
690 }
691 return sInstance;
692 }
693 }
694
695 /** Private constructor; @see init() */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700696 private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700697 mApp = app;
698 mPhone = phone;
699 mCM = PhoneGlobals.getInstance().mCM;
700 mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
701 mMainThreadHandler = new MainThreadHandler();
Derek Tan97ebb422014-09-05 16:55:38 -0700702 carrierPrivilegeConfigs =
703 PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700704 publish();
705 }
706
707 private void publish() {
708 if (DBG) log("publish: " + this);
709
710 ServiceManager.addService("phone", this);
711 }
712
Wink Saville36469e72014-06-11 15:17:00 -0700713 // returns phone associated with the subId.
714 // getPhone(0) returns default phone in single SIM mode.
715 private Phone getPhone(long subId) {
716 // FIXME: hack for the moment
717 return mPhone;
718 // return PhoneUtils.getPhoneUsingSubId(subId);
719 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700720 //
721 // Implementation of the ITelephony interface.
722 //
723
724 public void dial(String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700725 dialUsingSubId(getPreferredVoiceSubscription(), number);
726 }
727
728 public void dialUsingSubId(long subId, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700729 if (DBG) log("dial: " + number);
730 // No permission check needed here: This is just a wrapper around the
731 // ACTION_DIAL intent, which is available to any app since it puts up
732 // the UI before it does anything.
733
734 String url = createTelUrl(number);
735 if (url == null) {
736 return;
737 }
738
739 // PENDING: should we just silently fail if phone is offhook or ringing?
Wink Saville36469e72014-06-11 15:17:00 -0700740 PhoneConstants.State state = mCM.getState(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700741 if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
742 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
743 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Wink Saville36469e72014-06-11 15:17:00 -0700744 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700745 mApp.startActivity(intent);
746 }
747 }
748
749 public void call(String callingPackage, String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700750 callUsingSubId(getPreferredVoiceSubscription(), callingPackage, number);
751 }
752
753 public void callUsingSubId(long subId, String callingPackage, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700754 if (DBG) log("call: " + number);
755
756 // This is just a wrapper around the ACTION_CALL intent, but we still
757 // need to do a permission check since we're calling startActivity()
758 // from the context of the phone app.
759 enforceCallPermission();
760
761 if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
762 != AppOpsManager.MODE_ALLOWED) {
763 return;
764 }
765
766 String url = createTelUrl(number);
767 if (url == null) {
768 return;
769 }
770
771 Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
Wink Saville36469e72014-06-11 15:17:00 -0700772 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700773 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
774 mApp.startActivity(intent);
775 }
776
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700777 /**
778 * End a call based on call state
779 * @return true is a call was ended
780 */
781 public boolean endCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700782 return endCallUsingSubId(getDefaultSubscription());
783 }
784
785 /**
786 * End a call based on the call state of the subId
787 * @return true is a call was ended
788 */
789 public boolean endCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700790 enforceCallPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700791 return (Boolean) sendRequest(CMD_END_CALL, subId, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700792 }
793
794 public void answerRingingCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700795 answerRingingCallUsingSubId(getDefaultSubscription());
796 }
797
798 public void answerRingingCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700799 if (DBG) log("answerRingingCall...");
800 // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
801 // but that can probably wait till the big TelephonyManager API overhaul.
802 // For now, protect this call with the MODIFY_PHONE_STATE permission.
803 enforceModifyPermission();
804 sendRequestAsync(CMD_ANSWER_RINGING_CALL);
805 }
806
807 /**
808 * Make the actual telephony calls to implement answerRingingCall().
809 * This should only be called from the main thread of the Phone app.
810 * @see #answerRingingCall
811 *
812 * TODO: it would be nice to return true if we answered the call, or
813 * false if there wasn't actually a ringing incoming call, or some
814 * other error occurred. (In other words, pass back the return value
815 * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
816 * But that would require calling this method via sendRequest() rather
817 * than sendRequestAsync(), and right now we don't actually *need* that
818 * return value, so let's just return void for now.
819 */
820 private void answerRingingCallInternal() {
821 final boolean hasRingingCall = !mPhone.getRingingCall().isIdle();
822 if (hasRingingCall) {
823 final boolean hasActiveCall = !mPhone.getForegroundCall().isIdle();
824 final boolean hasHoldingCall = !mPhone.getBackgroundCall().isIdle();
825 if (hasActiveCall && hasHoldingCall) {
826 // Both lines are in use!
827 // TODO: provide a flag to let the caller specify what
828 // policy to use if both lines are in use. (The current
829 // behavior is hardwired to "answer incoming, end ongoing",
830 // which is how the CALL button is specced to behave.)
831 PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
832 return;
833 } else {
834 // answerCall() will automatically hold the current active
835 // call, if there is one.
836 PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
837 return;
838 }
839 } else {
840 // No call was ringing.
841 return;
842 }
843 }
844
845 public void silenceRinger() {
846 if (DBG) log("silenceRinger...");
847 // TODO: find a more appropriate permission to check here.
848 // (That can probably wait till the big TelephonyManager API overhaul.
849 // For now, protect this call with the MODIFY_PHONE_STATE permission.)
850 enforceModifyPermission();
851 sendRequestAsync(CMD_SILENCE_RINGER);
852 }
853
854 /**
855 * Internal implemenation of silenceRinger().
856 * This should only be called from the main thread of the Phone app.
857 * @see #silenceRinger
858 */
859 private void silenceRingerInternal() {
860 if ((mCM.getState() == PhoneConstants.State.RINGING)
861 && mApp.notifier.isRinging()) {
862 // Ringer is actually playing, so silence it.
863 if (DBG) log("silenceRingerInternal: silencing...");
864 mApp.notifier.silenceRinger();
865 }
866 }
867
868 public boolean isOffhook() {
Wink Saville36469e72014-06-11 15:17:00 -0700869 return isOffhookUsingSubId(getDefaultSubscription());
870 }
871
872 public boolean isOffhookUsingSubId(long subId) {
873 return (getPhone(subId).getState() == PhoneConstants.State.OFFHOOK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700874 }
875
876 public boolean isRinging() {
Wink Saville36469e72014-06-11 15:17:00 -0700877 return (isRingingUsingSubId(getDefaultSubscription()));
878 }
879
880 public boolean isRingingUsingSubId(long subId) {
881 return (getPhone(subId).getState() == PhoneConstants.State.RINGING);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700882 }
883
884 public boolean isIdle() {
Wink Saville36469e72014-06-11 15:17:00 -0700885 return isIdleUsingSubId(getDefaultSubscription());
886 }
887
888 public boolean isIdleUsingSubId(long subId) {
889 return (getPhone(subId).getState() == PhoneConstants.State.IDLE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700890 }
891
892 public boolean isSimPinEnabled() {
893 enforceReadPermission();
894 return (PhoneGlobals.getInstance().isSimPinEnabled());
895 }
896
897 public boolean supplyPin(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700898 return supplyPinUsingSubId(getDefaultSubscription(), pin);
899 }
900
901 public boolean supplyPinUsingSubId(long subId, String pin) {
902 int [] resultArray = supplyPinReportResultUsingSubId(subId, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700903 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
904 }
905
906 public boolean supplyPuk(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700907 return supplyPukUsingSubId(getDefaultSubscription(), puk, pin);
908 }
909
910 public boolean supplyPukUsingSubId(long subId, String puk, String pin) {
911 int [] resultArray = supplyPukReportResultUsingSubId(subId, puk, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700912 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
913 }
914
915 /** {@hide} */
916 public int[] supplyPinReportResult(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700917 return supplyPinReportResultUsingSubId(getDefaultSubscription(), pin);
918 }
919
920 public int[] supplyPinReportResultUsingSubId(long subId, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700921 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700922 final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700923 checkSimPin.start();
924 return checkSimPin.unlockSim(null, pin);
925 }
926
Wink Saville9de0f752013-10-22 19:04:03 -0700927 /** {@hide} */
928 public int[] supplyPukReportResult(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700929 return supplyPukReportResultUsingSubId(getDefaultSubscription(), puk, pin);
930 }
931
932 public int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700933 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700934 final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700935 checkSimPuk.start();
936 return checkSimPuk.unlockSim(puk, pin);
937 }
938
939 /**
Wink Saville9de0f752013-10-22 19:04:03 -0700940 * Helper thread to turn async call to SimCard#supplyPin into
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700941 * a synchronous one.
942 */
943 private static class UnlockSim extends Thread {
944
945 private final IccCard mSimCard;
946
947 private boolean mDone = false;
Wink Saville9de0f752013-10-22 19:04:03 -0700948 private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
949 private int mRetryCount = -1;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700950
951 // For replies from SimCard interface
952 private Handler mHandler;
953
954 // For async handler to identify request type
955 private static final int SUPPLY_PIN_COMPLETE = 100;
956
957 public UnlockSim(IccCard simCard) {
958 mSimCard = simCard;
959 }
960
961 @Override
962 public void run() {
963 Looper.prepare();
964 synchronized (UnlockSim.this) {
965 mHandler = new Handler() {
966 @Override
967 public void handleMessage(Message msg) {
968 AsyncResult ar = (AsyncResult) msg.obj;
969 switch (msg.what) {
970 case SUPPLY_PIN_COMPLETE:
971 Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
972 synchronized (UnlockSim.this) {
Wink Saville9de0f752013-10-22 19:04:03 -0700973 mRetryCount = msg.arg1;
974 if (ar.exception != null) {
975 if (ar.exception instanceof CommandException &&
976 ((CommandException)(ar.exception)).getCommandError()
977 == CommandException.Error.PASSWORD_INCORRECT) {
978 mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
979 } else {
980 mResult = PhoneConstants.PIN_GENERAL_FAILURE;
981 }
982 } else {
983 mResult = PhoneConstants.PIN_RESULT_SUCCESS;
984 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700985 mDone = true;
986 UnlockSim.this.notifyAll();
987 }
988 break;
989 }
990 }
991 };
992 UnlockSim.this.notifyAll();
993 }
994 Looper.loop();
995 }
996
997 /*
998 * Use PIN or PUK to unlock SIM card
999 *
1000 * If PUK is null, unlock SIM card with PIN
1001 *
1002 * If PUK is not null, unlock SIM card with PUK and set PIN code
1003 */
Wink Saville9de0f752013-10-22 19:04:03 -07001004 synchronized int[] unlockSim(String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001005
1006 while (mHandler == null) {
1007 try {
1008 wait();
1009 } catch (InterruptedException e) {
1010 Thread.currentThread().interrupt();
1011 }
1012 }
1013 Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
1014
1015 if (puk == null) {
1016 mSimCard.supplyPin(pin, callback);
1017 } else {
1018 mSimCard.supplyPuk(puk, pin, callback);
1019 }
1020
1021 while (!mDone) {
1022 try {
1023 Log.d(LOG_TAG, "wait for done");
1024 wait();
1025 } catch (InterruptedException e) {
1026 // Restore the interrupted status
1027 Thread.currentThread().interrupt();
1028 }
1029 }
1030 Log.d(LOG_TAG, "done");
Wink Saville9de0f752013-10-22 19:04:03 -07001031 int[] resultArray = new int[2];
1032 resultArray[0] = mResult;
1033 resultArray[1] = mRetryCount;
1034 return resultArray;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001035 }
1036 }
1037
1038 public void updateServiceLocation() {
Wink Saville36469e72014-06-11 15:17:00 -07001039 updateServiceLocationUsingSubId(getDefaultSubscription());
1040
1041 }
1042
1043 public void updateServiceLocationUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001044 // No permission check needed here: this call is harmless, and it's
1045 // needed for the ServiceState.requestStateUpdate() call (which is
1046 // already intentionally exposed to 3rd parties.)
Wink Saville36469e72014-06-11 15:17:00 -07001047 getPhone(subId).updateServiceLocation();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001048 }
1049
1050 public boolean isRadioOn() {
Wink Saville36469e72014-06-11 15:17:00 -07001051 return isRadioOnUsingSubId(getDefaultSubscription());
1052 }
1053
1054 public boolean isRadioOnUsingSubId(long subId) {
1055 return getPhone(subId).getServiceState().getState() != ServiceState.STATE_POWER_OFF;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001056 }
1057
1058 public void toggleRadioOnOff() {
Wink Saville36469e72014-06-11 15:17:00 -07001059 toggleRadioOnOffUsingSubId(getDefaultSubscription());
1060
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001061 }
Wink Saville36469e72014-06-11 15:17:00 -07001062
1063 public void toggleRadioOnOffUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001064 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001065 getPhone(subId).setRadioPower(!isRadioOnUsingSubId(subId));
1066 }
1067
1068 public boolean setRadio(boolean turnOn) {
1069 return setRadioUsingSubId(getDefaultSubscription(), turnOn);
1070 }
1071
1072 public boolean setRadioUsingSubId(long subId, boolean turnOn) {
1073 enforceModifyPermission();
1074 if ((getPhone(subId).getServiceState().getState() !=
1075 ServiceState.STATE_POWER_OFF) != turnOn) {
1076 toggleRadioOnOffUsingSubId(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001077 }
1078 return true;
1079 }
Wink Saville36469e72014-06-11 15:17:00 -07001080
Naveen Kalla1fd79bd2014-08-08 00:48:59 -07001081 public boolean needMobileRadioShutdown() {
1082 /*
1083 * If any of the Radios are available, it will need to be
1084 * shutdown. So return true if any Radio is available.
1085 */
1086 for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
1087 Phone phone = PhoneFactory.getPhone(i);
1088 if (phone != null && phone.isRadioAvailable()) return true;
1089 }
1090 logv(TelephonyManager.getDefault().getPhoneCount() + " Phones are shutdown.");
1091 return false;
1092 }
1093
1094 public void shutdownMobileRadios() {
1095 for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
1096 logv("Shutting down Phone " + i);
1097 shutdownRadioUsingPhoneId(i);
1098 }
1099 }
1100
1101 private void shutdownRadioUsingPhoneId(int phoneId) {
1102 enforceModifyPermission();
1103 Phone phone = PhoneFactory.getPhone(phoneId);
1104 if (phone != null && phone.isRadioAvailable()) {
1105 phone.shutdownRadio();
1106 }
1107 }
1108
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001109 public boolean setRadioPower(boolean turnOn) {
Wink Saville36469e72014-06-11 15:17:00 -07001110 return setRadioPowerUsingSubId(getDefaultSubscription(), turnOn);
1111 }
1112
1113 public boolean setRadioPowerUsingSubId(long subId, boolean turnOn) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001114 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001115 getPhone(subId).setRadioPower(turnOn);
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 enableDataConnectivity() {
1121 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001122 long subId = SubscriptionManager.getDefaultDataSubId();
1123 getPhone(subId).setDataEnabled(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001124 return true;
1125 }
1126
Wink Saville36469e72014-06-11 15:17:00 -07001127 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001128 public boolean disableDataConnectivity() {
1129 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001130 long subId = SubscriptionManager.getDefaultDataSubId();
1131 getPhone(subId).setDataEnabled(false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001132 return true;
1133 }
1134
Wink Saville36469e72014-06-11 15:17:00 -07001135 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001136 public boolean isDataConnectivityPossible() {
Wink Saville36469e72014-06-11 15:17:00 -07001137 long subId = SubscriptionManager.getDefaultDataSubId();
1138 return getPhone(subId).isDataConnectivityPossible();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001139 }
1140
1141 public boolean handlePinMmi(String dialString) {
Wink Saville36469e72014-06-11 15:17:00 -07001142 return handlePinMmiUsingSubId(getDefaultSubscription(), dialString);
1143 }
1144
1145 public boolean handlePinMmiUsingSubId(long subId, String dialString) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001146 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001147 return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001148 }
1149
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001150 public int getCallState() {
Wink Saville36469e72014-06-11 15:17:00 -07001151 return getCallStateUsingSubId(getDefaultSubscription());
1152 }
1153
1154 public int getCallStateUsingSubId(long subId) {
1155 return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001156 }
1157
1158 public int getDataState() {
Wink Saville36469e72014-06-11 15:17:00 -07001159 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1160 return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001161 }
1162
1163 public int getDataActivity() {
Wink Saville36469e72014-06-11 15:17:00 -07001164 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1165 return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001166 }
1167
1168 @Override
1169 public Bundle getCellLocation() {
1170 try {
1171 mApp.enforceCallingOrSelfPermission(
1172 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1173 } catch (SecurityException e) {
1174 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1175 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1176 // is the weaker precondition
1177 mApp.enforceCallingOrSelfPermission(
1178 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1179 }
1180
Jake Hambye994d462014-02-03 13:10:13 -08001181 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001182 if (DBG_LOC) log("getCellLocation: is active user");
1183 Bundle data = new Bundle();
1184 mPhone.getCellLocation().fillInNotifierBundle(data);
1185 return data;
1186 } else {
1187 if (DBG_LOC) log("getCellLocation: suppress non-active user");
1188 return null;
1189 }
1190 }
1191
1192 @Override
1193 public void enableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001194 enableLocationUpdatesUsingSubId(getDefaultSubscription());
1195 }
1196
1197 public void enableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001198 mApp.enforceCallingOrSelfPermission(
1199 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001200 getPhone(subId).enableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001201 }
1202
1203 @Override
1204 public void disableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001205 disableLocationUpdatesUsingSubId(getDefaultSubscription());
1206 }
1207
1208 public void disableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001209 mApp.enforceCallingOrSelfPermission(
1210 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001211 getPhone(subId).disableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001212 }
1213
1214 @Override
1215 @SuppressWarnings("unchecked")
1216 public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1217 try {
1218 mApp.enforceCallingOrSelfPermission(
1219 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1220 } catch (SecurityException e) {
1221 // If we have ACCESS_FINE_LOCATION permission, skip the check
1222 // for ACCESS_COARSE_LOCATION
1223 // A failure should throw the SecurityException from
1224 // ACCESS_COARSE_LOCATION since this is the weaker precondition
1225 mApp.enforceCallingOrSelfPermission(
1226 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1227 }
1228
1229 if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1230 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1231 return null;
1232 }
Jake Hambye994d462014-02-03 13:10:13 -08001233 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001234 if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1235
1236 ArrayList<NeighboringCellInfo> cells = null;
1237
1238 try {
1239 cells = (ArrayList<NeighboringCellInfo>) sendRequest(
Wink Saville36469e72014-06-11 15:17:00 -07001240 CMD_HANDLE_NEIGHBORING_CELL, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001241 } catch (RuntimeException e) {
Wink Saville36469e72014-06-11 15:17:00 -07001242 Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001243 }
1244 return cells;
1245 } else {
1246 if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1247 return null;
1248 }
1249 }
1250
1251
1252 @Override
1253 public List<CellInfo> getAllCellInfo() {
1254 try {
1255 mApp.enforceCallingOrSelfPermission(
1256 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1257 } catch (SecurityException e) {
1258 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1259 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1260 // is the weaker precondition
1261 mApp.enforceCallingOrSelfPermission(
1262 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1263 }
1264
Jake Hambye994d462014-02-03 13:10:13 -08001265 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001266 if (DBG_LOC) log("getAllCellInfo: is active user");
1267 return mPhone.getAllCellInfo();
1268 } else {
1269 if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1270 return null;
1271 }
1272 }
1273
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -07001274 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001275 public void setCellInfoListRate(int rateInMillis) {
1276 mPhone.setCellInfoListRate(rateInMillis);
1277 }
1278
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001279 //
1280 // Internal helper methods.
1281 //
1282
Jake Hambye994d462014-02-03 13:10:13 -08001283 private static boolean checkIfCallerIsSelfOrForegroundUser() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001284 boolean ok;
1285
1286 boolean self = Binder.getCallingUid() == Process.myUid();
1287 if (!self) {
1288 // Get the caller's user id then clear the calling identity
1289 // which will be restored in the finally clause.
1290 int callingUser = UserHandle.getCallingUserId();
1291 long ident = Binder.clearCallingIdentity();
1292
1293 try {
1294 // With calling identity cleared the current user is the foreground user.
1295 int foregroundUser = ActivityManager.getCurrentUser();
1296 ok = (foregroundUser == callingUser);
1297 if (DBG_LOC) {
1298 log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1299 + " callingUser=" + callingUser + " ok=" + ok);
1300 }
1301 } catch (Exception ex) {
1302 if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1303 ok = false;
1304 } finally {
1305 Binder.restoreCallingIdentity(ident);
1306 }
1307 } else {
1308 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1309 ok = true;
1310 }
1311 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1312 return ok;
1313 }
1314
1315 /**
1316 * Make sure the caller has the READ_PHONE_STATE permission.
1317 *
1318 * @throws SecurityException if the caller does not have the required permission
1319 */
1320 private void enforceReadPermission() {
1321 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
1322 }
1323
1324 /**
1325 * Make sure the caller has the MODIFY_PHONE_STATE permission.
1326 *
1327 * @throws SecurityException if the caller does not have the required permission
1328 */
1329 private void enforceModifyPermission() {
1330 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1331 }
1332
1333 /**
Junda Liua2e36012014-07-09 18:30:01 -07001334 * Make sure either system app or the caller has carrier privilege.
1335 *
1336 * @throws SecurityException if the caller does not have the required permission/privilege
1337 */
1338 private void enforceModifyPermissionOrCarrierPrivilege() {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001339 int permission = mApp.checkCallingOrSelfPermission(
1340 android.Manifest.permission.MODIFY_PHONE_STATE);
1341 if (permission == PackageManager.PERMISSION_GRANTED) {
1342 return;
1343 }
1344
1345 log("No modify permission, check carrier privilege next.");
1346 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1347 loge("No Carrier Privilege.");
1348 throw new SecurityException("No modify permission or carrier privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001349 }
1350 }
1351
1352 /**
1353 * Make sure the caller has carrier privilege.
1354 *
1355 * @throws SecurityException if the caller does not have the required permission
1356 */
1357 private void enforceCarrierPrivilege() {
1358 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001359 loge("No Carrier Privilege.");
1360 throw new SecurityException("No Carrier Privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001361 }
1362 }
1363
1364 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001365 * Make sure the caller has the CALL_PHONE permission.
1366 *
1367 * @throws SecurityException if the caller does not have the required permission
1368 */
1369 private void enforceCallPermission() {
1370 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1371 }
1372
Shishir Agrawal566b7612013-10-28 14:41:00 -07001373 /**
Gabriel Peal36ebb0d2014-03-20 09:20:43 -07001374 * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1375 *
1376 * @throws SecurityException if the caller does not have the required permission
1377 */
1378 private void enforcePrivilegedPhoneStatePermission() {
1379 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1380 null);
1381 }
1382
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001383 private String createTelUrl(String number) {
1384 if (TextUtils.isEmpty(number)) {
1385 return null;
1386 }
1387
Jake Hambye994d462014-02-03 13:10:13 -08001388 return "tel:" + number;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001389 }
1390
Ihab Awadf9e92732013-12-05 18:02:52 -08001391 private static void log(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001392 Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1393 }
1394
Naveen Kalla1fd79bd2014-08-08 00:48:59 -07001395 private static void logv(String msg) {
1396 Log.v(LOG_TAG, "[PhoneIntfMgr] " + msg);
1397 }
1398
Ihab Awadf9e92732013-12-05 18:02:52 -08001399 private static void loge(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001400 Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1401 }
1402
1403 public int getActivePhoneType() {
Wink Saville36469e72014-06-11 15:17:00 -07001404 return getActivePhoneTypeUsingSubId(getDefaultSubscription());
1405 }
1406
1407 public int getActivePhoneTypeUsingSubId(long subId) {
1408 return getPhone(subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001409 }
1410
1411 /**
1412 * Returns the CDMA ERI icon index to display
1413 */
1414 public int getCdmaEriIconIndex() {
Wink Saville36469e72014-06-11 15:17:00 -07001415 return getCdmaEriIconIndexUsingSubId(getDefaultSubscription());
1416
1417 }
1418
1419 public int getCdmaEriIconIndexUsingSubId(long subId) {
1420 return getPhone(subId).getCdmaEriIconIndex();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001421 }
1422
1423 /**
1424 * Returns the CDMA ERI icon mode,
1425 * 0 - ON
1426 * 1 - FLASHING
1427 */
1428 public int getCdmaEriIconMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001429 return getCdmaEriIconModeUsingSubId(getDefaultSubscription());
1430 }
1431
1432 public int getCdmaEriIconModeUsingSubId(long subId) {
1433 return getPhone(subId).getCdmaEriIconMode();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001434 }
1435
1436 /**
1437 * Returns the CDMA ERI text,
1438 */
1439 public String getCdmaEriText() {
Wink Saville36469e72014-06-11 15:17:00 -07001440 return getCdmaEriTextUsingSubId(getDefaultSubscription());
1441 }
1442
1443 public String getCdmaEriTextUsingSubId(long subId) {
1444 return getPhone(subId).getCdmaEriText();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001445 }
1446
1447 /**
Junda Liuca05d5d2014-08-14 22:36:34 -07001448 * Returns the CDMA MDN.
1449 */
1450 public String getCdmaMdn(long subId) {
1451 enforceModifyPermissionOrCarrierPrivilege();
1452 if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
1453 return getPhone(subId).getLine1Number();
1454 } else {
1455 return null;
1456 }
1457 }
1458
1459 /**
1460 * Returns the CDMA MIN.
1461 */
1462 public String getCdmaMin(long subId) {
1463 enforceModifyPermissionOrCarrierPrivilege();
1464 if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
1465 return getPhone(subId).getCdmaMin();
1466 } else {
1467 return null;
1468 }
1469 }
1470
1471 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001472 * Returns true if CDMA provisioning needs to run.
1473 */
1474 public boolean needsOtaServiceProvisioning() {
1475 return mPhone.needsOtaServiceProvisioning();
1476 }
1477
1478 /**
1479 * Returns the unread count of voicemails
1480 */
1481 public int getVoiceMessageCount() {
Wink Saville36469e72014-06-11 15:17:00 -07001482 return getVoiceMessageCountUsingSubId(getDefaultSubscription());
1483 }
1484
1485 /**
1486 * Returns the unread count of voicemails for a subId
1487 */
1488 public int getVoiceMessageCountUsingSubId( long subId) {
1489 return getPhone(subId).getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001490 }
1491
1492 /**
1493 * Returns the data network type
1494 *
1495 * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1496 */
1497 @Override
1498 public int getNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001499 return getNetworkTypeUsingSubId(getDefaultSubscription());
1500 }
1501
1502 /**
1503 * Returns the network type for a subId
1504 */
1505 @Override
1506 public int getNetworkTypeUsingSubId(long subId) {
1507 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001508 }
1509
1510 /**
1511 * Returns the data network type
1512 */
1513 @Override
1514 public int getDataNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001515 return getDataNetworkTypeUsingSubId(getDefaultSubscription());
1516 }
1517
1518 /**
1519 * Returns the data network type for a subId
1520 */
1521 @Override
1522 public int getDataNetworkTypeUsingSubId(long subId) {
1523 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001524 }
1525
1526 /**
1527 * Returns the data network type
1528 */
1529 @Override
1530 public int getVoiceNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001531 return getVoiceNetworkTypeUsingSubId(getDefaultSubscription());
1532 }
1533
1534 /**
1535 * Returns the Voice network type for a subId
1536 */
1537 @Override
1538 public int getVoiceNetworkTypeUsingSubId(long subId) {
1539 return getPhone(subId).getServiceState().getVoiceNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001540 }
1541
1542 /**
1543 * @return true if a ICC card is present
1544 */
1545 public boolean hasIccCard() {
Wink Saville36469e72014-06-11 15:17:00 -07001546 // FIXME Make changes to pass defaultSimId of type int
1547 return hasIccCardUsingSlotId(getDefaultSubscription());
1548 }
1549
1550 /**
1551 * @return true if a ICC card is present for a slotId
1552 */
1553 public boolean hasIccCardUsingSlotId(long slotId) {
1554 return getPhone(slotId).getIccCard().hasIccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001555 }
1556
1557 /**
1558 * Return if the current radio is LTE on CDMA. This
1559 * is a tri-state return value as for a period of time
1560 * the mode may be unknown.
1561 *
1562 * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
Jake Hambye994d462014-02-03 13:10:13 -08001563 * or {@link Phone#LTE_ON_CDMA_TRUE}
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001564 */
1565 public int getLteOnCdmaMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001566 return getLteOnCdmaModeUsingSubId(getDefaultSubscription());
1567 }
1568
1569 public int getLteOnCdmaModeUsingSubId(long subId) {
1570 return getPhone(subId).getLteOnCdmaMode();
1571 }
1572
1573 public void setPhone(Phone phone) {
1574 mPhone = phone;
1575 }
1576
1577 /**
1578 * {@hide}
1579 * Returns Default subId, 0 in the case of single standby.
1580 */
1581 private long getDefaultSubscription() {
1582 return SubscriptionManager.getDefaultSubId();
1583 }
1584
1585 private long getPreferredVoiceSubscription() {
1586 return SubscriptionManager.getDefaultVoiceSubId();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001587 }
Ihab Awadf2177b72013-11-25 13:33:23 -08001588
1589 /**
1590 * @see android.telephony.TelephonyManager.WifiCallingChoices
1591 */
1592 public int getWhenToMakeWifiCalls() {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001593 return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1594 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
Ihab Awadf2177b72013-11-25 13:33:23 -08001595 }
1596
1597 /**
1598 * @see android.telephony.TelephonyManager.WifiCallingChoices
1599 */
1600 public void setWhenToMakeWifiCalls(int preference) {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001601 if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1602 Settings.System.putInt(mPhone.getContext().getContentResolver(),
1603 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
Ihab Awadf9e92732013-12-05 18:02:52 -08001604 }
1605
Sailesh Nepald1e68152013-12-12 19:08:02 -08001606 private static int getWhenToMakeWifiCallsDefaultPreference() {
Santos Cordonda120f42014-08-06 04:44:34 -07001607 // TODO: Use a build property to choose this value.
Evan Charlton9829e882013-12-19 15:30:38 -08001608 return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
Ihab Awadf2177b72013-11-25 13:33:23 -08001609 }
Shishir Agrawal69f68122013-12-16 17:25:49 -08001610
Shishir Agrawal566b7612013-10-28 14:41:00 -07001611 @Override
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001612 public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID) {
Junda Liua2e36012014-07-09 18:30:01 -07001613 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001614
1615 if (DBG) log("iccOpenLogicalChannel: " + AID);
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001616 IccOpenLogicalChannelResponse response = (IccOpenLogicalChannelResponse)sendRequest(
1617 CMD_OPEN_CHANNEL, AID);
1618 if (DBG) log("iccOpenLogicalChannel: " + response);
1619 return response;
Shishir Agrawal566b7612013-10-28 14:41:00 -07001620 }
1621
1622 @Override
1623 public boolean iccCloseLogicalChannel(int channel) {
Junda Liua2e36012014-07-09 18:30:01 -07001624 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001625
1626 if (DBG) log("iccCloseLogicalChannel: " + channel);
1627 if (channel < 0) {
1628 return false;
1629 }
Jake Hambye994d462014-02-03 13:10:13 -08001630 Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
Shishir Agrawal566b7612013-10-28 14:41:00 -07001631 if (DBG) log("iccCloseLogicalChannel: " + success);
1632 return success;
1633 }
1634
1635 @Override
1636 public String iccTransmitApduLogicalChannel(int channel, int cla,
1637 int command, int p1, int p2, int p3, String data) {
Junda Liua2e36012014-07-09 18:30:01 -07001638 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001639
1640 if (DBG) {
1641 log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1642 " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1643 " data=" + data);
1644 }
1645
1646 if (channel < 0) {
1647 return "";
1648 }
1649
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001650 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_LOGICAL_CHANNEL,
Shishir Agrawal566b7612013-10-28 14:41:00 -07001651 new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1652 if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1653
Shishir Agrawal566b7612013-10-28 14:41:00 -07001654 // Append the returned status code to the end of the response payload.
1655 String s = Integer.toHexString(
1656 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
Shishir Agrawal5ec14172014-08-05 17:05:45 -07001657 if (response.payload != null) {
1658 s = IccUtils.bytesToHexString(response.payload) + s;
1659 }
Shishir Agrawal566b7612013-10-28 14:41:00 -07001660 return s;
1661 }
Jake Hambye994d462014-02-03 13:10:13 -08001662
Evan Charltonc66da362014-05-16 14:06:40 -07001663 @Override
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001664 public String iccTransmitApduBasicChannel(int cla, int command, int p1, int p2,
1665 int p3, String data) {
1666 enforceModifyPermissionOrCarrierPrivilege();
1667
1668 if (DBG) {
1669 log("iccTransmitApduBasicChannel: cla=" + cla + " cmd=" + command + " p1="
1670 + p1 + " p2=" + p2 + " p3=" + p3 + " data=" + data);
1671 }
1672
1673 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_BASIC_CHANNEL,
1674 new IccAPDUArgument(0, cla, command, p1, p2, p3, data));
1675 if (DBG) log("iccTransmitApduBasicChannel: " + response);
1676
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001677 // Append the returned status code to the end of the response payload.
1678 String s = Integer.toHexString(
1679 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
Shishir Agrawal5ec14172014-08-05 17:05:45 -07001680 if (response.payload != null) {
1681 s = IccUtils.bytesToHexString(response.payload) + s;
1682 }
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001683 return s;
1684 }
1685
1686 @Override
1687 public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
1688 String filePath) {
1689 enforceModifyPermissionOrCarrierPrivilege();
1690
1691 if (DBG) {
1692 log("Exchange SIM_IO " + fileID + ":" + command + " " +
1693 p1 + " " + p2 + " " + p3 + ":" + filePath);
1694 }
1695
1696 IccIoResult response =
1697 (IccIoResult)sendRequest(CMD_EXCHANGE_SIM_IO,
1698 new IccAPDUArgument(fileID, command, -1, p1, p2, p3, filePath));
1699
1700 if (DBG) {
1701 log("Exchange SIM_IO [R]" + response);
1702 }
1703
1704 byte[] result = null;
1705 int length = 2;
1706 if (response.payload != null) {
1707 length = 2 + response.payload.length;
1708 result = new byte[length];
1709 System.arraycopy(response.payload, 0, result, 0, response.payload.length);
1710 } else {
1711 result = new byte[length];
1712 }
1713
1714 result[length - 1] = (byte) response.sw2;
1715 result[length - 2] = (byte) response.sw1;
1716 return result;
1717 }
1718
1719 @Override
Evan Charltonc66da362014-05-16 14:06:40 -07001720 public String sendEnvelopeWithStatus(String content) {
Junda Liua2e36012014-07-09 18:30:01 -07001721 enforceModifyPermissionOrCarrierPrivilege();
Evan Charltonc66da362014-05-16 14:06:40 -07001722
1723 IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
1724 if (response.payload == null) {
1725 return "";
1726 }
1727
1728 // Append the returned status code to the end of the response payload.
1729 String s = Integer.toHexString(
1730 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1731 s = IccUtils.bytesToHexString(response.payload) + s;
1732 return s;
1733 }
1734
Jake Hambye994d462014-02-03 13:10:13 -08001735 /**
1736 * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1737 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1738 *
1739 * @param itemID the ID of the item to read
1740 * @return the NV item as a String, or null on error.
1741 */
1742 @Override
1743 public String nvReadItem(int itemID) {
Junda Liua2e36012014-07-09 18:30:01 -07001744 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001745 if (DBG) log("nvReadItem: item " + itemID);
1746 String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
1747 if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
1748 return value;
1749 }
1750
1751 /**
1752 * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1753 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1754 *
1755 * @param itemID the ID of the item to read
1756 * @param itemValue the value to write, as a String
1757 * @return true on success; false on any failure
1758 */
1759 @Override
1760 public boolean nvWriteItem(int itemID, String itemValue) {
Junda Liua2e36012014-07-09 18:30:01 -07001761 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001762 if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
1763 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
1764 new Pair<Integer, String>(itemID, itemValue));
1765 if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
1766 return success;
1767 }
1768
1769 /**
1770 * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
1771 * Used for device configuration by some CDMA operators.
1772 *
1773 * @param preferredRoamingList byte array containing the new PRL
1774 * @return true on success; false on any failure
1775 */
1776 @Override
1777 public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
Junda Liua2e36012014-07-09 18:30:01 -07001778 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001779 if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
1780 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
1781 if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
1782 return success;
1783 }
1784
1785 /**
1786 * Perform the specified type of NV config reset.
1787 * Used for device configuration by some CDMA operators.
1788 *
1789 * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
1790 * @return true on success; false on any failure
1791 */
1792 @Override
1793 public boolean nvResetConfig(int resetType) {
Junda Liua2e36012014-07-09 18:30:01 -07001794 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001795 if (DBG) log("nvResetConfig: type " + resetType);
1796 Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
1797 if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
1798 return success;
1799 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001800
1801 /**
Wink Saville36469e72014-06-11 15:17:00 -07001802 * {@hide}
1803 * Returns Default sim, 0 in the case of single standby.
1804 */
1805 public int getDefaultSim() {
1806 //TODO Need to get it from Telephony Devcontroller
1807 return 0;
1808 }
1809
ram87fca6f2014-07-18 18:58:44 +05301810 public String[] getPcscfAddress(String apnType) {
Wink Saville36469e72014-06-11 15:17:00 -07001811 enforceReadPermission();
ram87fca6f2014-07-18 18:58:44 +05301812 return mPhone.getPcscfAddress(apnType);
Wink Saville36469e72014-06-11 15:17:00 -07001813 }
1814
1815 public void setImsRegistrationState(boolean registered) {
1816 enforceModifyPermission();
1817 mPhone.setImsRegistrationState(registered);
1818 }
1819
1820 /**
Junda Liu84d15a22014-07-02 11:21:04 -07001821 * Get the calculated preferred network type.
1822 * Used for debugging incorrect network type.
1823 *
1824 * @return the preferred network type, defined in RILConstants.java.
1825 */
1826 @Override
1827 public int getCalculatedPreferredNetworkType() {
1828 enforceReadPermission();
1829 return PhoneFactory.calculatePreferredNetworkType(mPhone.getContext());
1830 }
1831
1832 /**
Jake Hamby7c27be32014-03-03 13:25:59 -08001833 * Get the preferred network type.
1834 * Used for device configuration by some CDMA operators.
1835 *
1836 * @return the preferred network type, defined in RILConstants.java.
1837 */
1838 @Override
1839 public int getPreferredNetworkType() {
Junda Liua2e36012014-07-09 18:30:01 -07001840 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001841 if (DBG) log("getPreferredNetworkType");
1842 int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null);
1843 int networkType = (result != null ? result[0] : -1);
1844 if (DBG) log("getPreferredNetworkType: " + networkType);
1845 return networkType;
1846 }
1847
1848 /**
1849 * Set the preferred network type.
1850 * Used for device configuration by some CDMA operators.
1851 *
1852 * @param networkType the preferred network type, defined in RILConstants.java.
1853 * @return true on success; false on any failure.
1854 */
1855 @Override
1856 public boolean setPreferredNetworkType(int networkType) {
Junda Liua2e36012014-07-09 18:30:01 -07001857 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001858 if (DBG) log("setPreferredNetworkType: type " + networkType);
1859 Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType);
1860 if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
Junda Liu80bc0d12014-07-14 16:36:44 -07001861 if (success) {
1862 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1863 Settings.Global.PREFERRED_NETWORK_MODE, networkType);
1864 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001865 return success;
1866 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001867
1868 /**
1869 * Set mobile data enabled
1870 * Used by the user through settings etc to turn on/off mobile data
1871 *
1872 * @param enable {@code true} turn turn data on, else {@code false}
1873 */
1874 @Override
1875 public void setDataEnabled(boolean enable) {
1876 enforceModifyPermission();
1877 mPhone.setDataEnabled(enable);
1878 }
1879
1880 /**
Robert Greenwalt646120a2014-05-23 11:54:03 -07001881 * Get whether mobile data is enabled.
1882 *
1883 * Note that this used to be available from ConnectivityService, gated by
1884 * ACCESS_NETWORK_STATE permission, so this will accept either that or
1885 * our MODIFY_PHONE_STATE.
Robert Greenwalted86e582014-05-21 20:03:20 -07001886 *
1887 * @return {@code true} if data is enabled else {@code false}
1888 */
1889 @Override
1890 public boolean getDataEnabled() {
Robert Greenwalt646120a2014-05-23 11:54:03 -07001891 try {
1892 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
1893 null);
1894 } catch (Exception e) {
1895 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
1896 null);
1897 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001898 return mPhone.getDataEnabled();
1899 }
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001900
1901 @Override
1902 public int hasCarrierPrivileges() {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001903 UiccCard card = UiccController.getInstance().getUiccCard();
1904 if (card == null) {
1905 loge("hasCarrierPrivileges: No UICC");
1906 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1907 }
1908 return card.getCarrierPrivilegeStatusForCurrentTransaction(
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001909 mPhone.getContext().getPackageManager());
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001910 }
Junda Liu29340342014-07-10 15:23:27 -07001911
1912 @Override
Shishir Agrawal6d5a2852014-07-11 16:32:57 -07001913 public int checkCarrierPrivilegesForPackage(String pkgname) {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001914 UiccCard card = UiccController.getInstance().getUiccCard();
1915 if (card == null) {
1916 loge("checkCarrierPrivilegesForPackage: No UICC");
1917 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1918 }
1919 return card.getCarrierPrivilegeStatus(mPhone.getContext().getPackageManager(), pkgname);
Junda Liu29340342014-07-10 15:23:27 -07001920 }
Derek Tan89e89d42014-07-08 17:00:10 -07001921
1922 @Override
Diego Pontorieroaf74c862014-08-28 11:51:16 -07001923 public List<String> getCarrierPackageNamesForIntent(Intent intent) {
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001924 UiccCard card = UiccController.getInstance().getUiccCard();
1925 if (card == null) {
Diego Pontorieroaf74c862014-08-28 11:51:16 -07001926 loge("getCarrierPackageNamesForIntent: No UICC");
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001927 return null ;
1928 }
Diego Pontorieroaf74c862014-08-28 11:51:16 -07001929 return card.getCarrierPackageNamesForIntent(
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001930 mPhone.getContext().getPackageManager(), intent);
1931 }
1932
Derek Tan97ebb422014-09-05 16:55:38 -07001933 private String getIccId(long subId) {
1934 UiccCard card = getPhone(subId).getUiccCard();
1935 if (card == null) {
1936 loge("getIccId: No UICC");
1937 return null;
1938 }
1939 String iccId = card.getIccId();
1940 if (TextUtils.isEmpty(iccId)) {
1941 loge("getIccId: ICC ID is null or empty.");
1942 return null;
1943 }
1944 return iccId;
1945 }
1946
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001947 @Override
Derek Tan89e89d42014-07-08 17:00:10 -07001948 public void enableSimplifiedNetworkSettings(long subId, boolean enable) {
Derek Tan352d8cd2014-07-12 12:57:11 -07001949 enforceModifyPermissionOrCarrierPrivilege();
Derek Tan97ebb422014-09-05 16:55:38 -07001950
1951 String iccId = getIccId(subId);
1952 if (iccId != null) {
1953 String snsPrefKey = PREF_CARRIERS_SIMPLIFIED_NETWORK_SETTINGS_PREFIX + iccId;
1954 SharedPreferences.Editor editor = carrierPrivilegeConfigs.edit();
1955 if (enable) {
1956 editor.putBoolean(snsPrefKey, true);
1957 } else {
1958 editor.remove(snsPrefKey);
1959 }
1960 editor.commit();
Derek Tan89e89d42014-07-08 17:00:10 -07001961 }
1962 }
1963
1964 @Override
1965 public boolean getSimplifiedNetworkSettingsEnabled(long subId) {
1966 enforceReadPermission();
Derek Tan97ebb422014-09-05 16:55:38 -07001967 String iccId = getIccId(subId);
1968 if (iccId != null) {
1969 String snsPrefKey = PREF_CARRIERS_SIMPLIFIED_NETWORK_SETTINGS_PREFIX + iccId;
1970 return carrierPrivilegeConfigs.getBoolean(snsPrefKey, false);
1971 }
1972 return false;
Derek Tan89e89d42014-07-08 17:00:10 -07001973 }
Derek Tan7226c842014-07-02 17:42:23 -07001974
1975 @Override
1976 public void setLine1NumberForDisplay(long subId, String alphaTag, String number) {
Derek Tan352d8cd2014-07-12 12:57:11 -07001977 enforceModifyPermissionOrCarrierPrivilege();
Derek Tan97ebb422014-09-05 16:55:38 -07001978
1979 String iccId = getIccId(subId);
1980 if (iccId != null) {
1981 String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
1982 SharedPreferences.Editor editor = carrierPrivilegeConfigs.edit();
1983 if (alphaTag == null) {
1984 editor.remove(alphaTagPrefKey);
1985 } else {
1986 editor.putString(alphaTagPrefKey, alphaTag);
1987 }
1988
1989 String numberPrefKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
1990 if (number == null) {
1991 editor.remove(numberPrefKey);
1992 } else {
1993 editor.putString(numberPrefKey, number);
1994 }
1995 editor.commit();
1996 }
Derek Tan7226c842014-07-02 17:42:23 -07001997 }
1998
1999 @Override
2000 public String getLine1NumberForDisplay(long subId) {
2001 enforceReadPermission();
Derek Tan97ebb422014-09-05 16:55:38 -07002002
2003 String iccId = getIccId(subId);
2004 if (iccId != null) {
2005 String numberPrefKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
2006 return carrierPrivilegeConfigs.getString(numberPrefKey, null);
Derek Tan7226c842014-07-02 17:42:23 -07002007 }
Derek Tan97ebb422014-09-05 16:55:38 -07002008 return null;
Derek Tan7226c842014-07-02 17:42:23 -07002009 }
2010
2011 @Override
2012 public String getLine1AlphaTagForDisplay(long subId) {
2013 enforceReadPermission();
Derek Tan97ebb422014-09-05 16:55:38 -07002014
2015 String iccId = getIccId(subId);
2016 if (iccId != null) {
2017 String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
2018 return carrierPrivilegeConfigs.getString(alphaTagPrefKey, null);
Derek Tan7226c842014-07-02 17:42:23 -07002019 }
Derek Tan97ebb422014-09-05 16:55:38 -07002020 return null;
Derek Tan7226c842014-07-02 17:42:23 -07002021 }
Shishir Agrawalb1ebf8c2014-07-17 16:32:41 -07002022
2023 @Override
Shishir Agrawala3dfd752014-09-04 13:25:42 -07002024 public boolean setOperatorBrandOverride(String brand) {
Shishir Agrawalb1ebf8c2014-07-17 16:32:41 -07002025 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawala3dfd752014-09-04 13:25:42 -07002026 return mPhone.setOperatorBrandOverride(brand);
Shishir Agrawalb1ebf8c2014-07-17 16:32:41 -07002027 }
Steven Liu4bf01bc2014-07-17 11:05:29 -05002028
2029 @Override
2030 public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
2031 enforceModifyPermission();
2032
2033 int returnValue = 0;
2034 try {
2035 AsyncResult result = (AsyncResult)sendRequest(CMD_INVOKE_OEM_RIL_REQUEST_RAW, oemReq);
2036 if(result.exception == null) {
2037 if (result.result != null) {
2038 byte[] responseData = (byte[])(result.result);
2039 if(responseData.length > oemResp.length) {
2040 Log.w(LOG_TAG, "Buffer to copy response too small: Response length is " +
2041 responseData.length + "bytes. Buffer Size is " +
2042 oemResp.length + "bytes.");
2043 }
2044 System.arraycopy(responseData, 0, oemResp, 0, responseData.length);
2045 returnValue = responseData.length;
2046 }
2047 } else {
2048 CommandException ex = (CommandException) result.exception;
2049 returnValue = ex.getCommandError().ordinal();
2050 if(returnValue > 0) returnValue *= -1;
2051 }
2052 } catch (RuntimeException e) {
2053 Log.w(LOG_TAG, "sendOemRilRequestRaw: Runtime Exception");
2054 returnValue = (CommandException.Error.GENERIC_FAILURE.ordinal());
2055 if(returnValue > 0) returnValue *= -1;
2056 }
2057
2058 return returnValue;
2059 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07002060}