blob: 3ae99e79e4885f94153a16d42866812c40b7554f [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.phone;
18
19import android.app.ActivityManager;
20import android.app.AppOpsManager;
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -070021import android.content.ComponentName;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070022import android.content.Context;
23import android.content.Intent;
Shishir Agrawal60f9c952014-06-23 12:00:43 -070024import android.content.pm.PackageInfo;
25import android.content.pm.PackageManager;
26import android.content.pm.Signature;
Wink Saville36469e72014-06-11 15:17:00 -070027import android.net.ConnectivityManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070028import android.net.Uri;
29import android.os.AsyncResult;
30import android.os.Binder;
31import android.os.Bundle;
32import android.os.Handler;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070033import android.os.IBinder;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070034import android.os.Looper;
35import android.os.Message;
36import android.os.Process;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070037import android.os.RemoteException;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070038import android.os.ServiceManager;
39import android.os.UserHandle;
Ihab Awadf2177b72013-11-25 13:33:23 -080040import android.provider.Settings;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070041import android.telephony.CellInfo;
Jake Hambye994d462014-02-03 13:10:13 -080042import android.telephony.NeighboringCellInfo;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070043import android.telephony.ServiceState;
Wink Saville36469e72014-06-11 15:17:00 -070044import android.telephony.SubscriptionManager;
Ihab Awadf2177b72013-11-25 13:33:23 -080045import android.telephony.TelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070046import android.text.TextUtils;
47import android.util.Log;
Jake Hambye994d462014-02-03 13:10:13 -080048import android.util.Pair;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070049
Shishir Agrawal566b7612013-10-28 14:41:00 -070050import com.android.internal.telephony.CallManager;
51import com.android.internal.telephony.CommandException;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070052import com.android.internal.telephony.Connection;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070053import com.android.internal.telephony.DefaultPhoneNotifier;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070054import com.android.internal.telephony.ITelephony;
Jake Hambye994d462014-02-03 13:10:13 -080055import com.android.internal.telephony.IccCard;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070056import com.android.internal.telephony.Phone;
Wink Saville36469e72014-06-11 15:17:00 -070057import com.android.internal.telephony.PhoneFactory;
58import com.android.internal.telephony.CallManager;
59import com.android.internal.telephony.CommandException;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070060import com.android.internal.telephony.PhoneConstants;
Wink Saville36469e72014-06-11 15:17:00 -070061import com.android.internal.telephony.dataconnection.DctController;
Derek Tan7226c842014-07-02 17:42:23 -070062import com.android.internal.telephony.uicc.AdnRecord;
Shishir Agrawal566b7612013-10-28 14:41:00 -070063import com.android.internal.telephony.uicc.IccIoResult;
64import com.android.internal.telephony.uicc.IccUtils;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -070065import com.android.internal.telephony.uicc.UiccCard;
Shishir Agrawal60f9c952014-06-23 12:00:43 -070066import com.android.internal.telephony.uicc.UiccCarrierPrivilegeRules;
Shishir Agrawal566b7612013-10-28 14:41:00 -070067import com.android.internal.telephony.uicc.UiccController;
Jake Hambye994d462014-02-03 13:10:13 -080068import com.android.internal.util.HexDump;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070069
Wink Saville36469e72014-06-11 15:17:00 -070070import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
71
Santos Cordon7d4ddf62013-07-10 11:58:08 -070072import java.util.ArrayList;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070073import java.util.HashMap;
Derek Tan89e89d42014-07-08 17:00:10 -070074import java.util.HashSet;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070075import java.util.Iterator;
Jake Hambye994d462014-02-03 13:10:13 -080076import java.util.List;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070077import java.util.Map;
Derek Tan89e89d42014-07-08 17:00:10 -070078import java.util.Set;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070079
80/**
81 * Implementation of the ITelephony interface.
82 */
Santos Cordon117fee72014-05-16 17:56:12 -070083public class PhoneInterfaceManager extends ITelephony.Stub {
Santos Cordon7d4ddf62013-07-10 11:58:08 -070084 private static final String LOG_TAG = "PhoneInterfaceManager";
85 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
86 private static final boolean DBG_LOC = false;
87
88 // Message codes used with mMainThreadHandler
89 private static final int CMD_HANDLE_PIN_MMI = 1;
90 private static final int CMD_HANDLE_NEIGHBORING_CELL = 2;
91 private static final int EVENT_NEIGHBORING_CELL_DONE = 3;
92 private static final int CMD_ANSWER_RINGING_CALL = 4;
93 private static final int CMD_END_CALL = 5; // not used yet
94 private static final int CMD_SILENCE_RINGER = 6;
Shishir Agrawal566b7612013-10-28 14:41:00 -070095 private static final int CMD_TRANSMIT_APDU = 7;
96 private static final int EVENT_TRANSMIT_APDU_DONE = 8;
97 private static final int CMD_OPEN_CHANNEL = 9;
98 private static final int EVENT_OPEN_CHANNEL_DONE = 10;
99 private static final int CMD_CLOSE_CHANNEL = 11;
100 private static final int EVENT_CLOSE_CHANNEL_DONE = 12;
Jake Hambye994d462014-02-03 13:10:13 -0800101 private static final int CMD_NV_READ_ITEM = 13;
102 private static final int EVENT_NV_READ_ITEM_DONE = 14;
103 private static final int CMD_NV_WRITE_ITEM = 15;
104 private static final int EVENT_NV_WRITE_ITEM_DONE = 16;
105 private static final int CMD_NV_WRITE_CDMA_PRL = 17;
106 private static final int EVENT_NV_WRITE_CDMA_PRL_DONE = 18;
107 private static final int CMD_NV_RESET_CONFIG = 19;
108 private static final int EVENT_NV_RESET_CONFIG_DONE = 20;
Jake Hamby7c27be32014-03-03 13:25:59 -0800109 private static final int CMD_GET_PREFERRED_NETWORK_TYPE = 21;
110 private static final int EVENT_GET_PREFERRED_NETWORK_TYPE_DONE = 22;
111 private static final int CMD_SET_PREFERRED_NETWORK_TYPE = 23;
112 private static final int EVENT_SET_PREFERRED_NETWORK_TYPE_DONE = 24;
Sailesh Nepal35b59452014-03-06 09:26:56 -0800113 private static final int CMD_SEND_ENVELOPE = 25;
114 private static final int EVENT_SEND_ENVELOPE_DONE = 26;
Junda Liu787bc7e2014-06-30 13:38:02 -0700115 private static final int CMD_SET_CDMA_SUBSCRIPTION = 27;
116 private static final int EVENT_SET_CDMA_SUBSCRIPTION_DONE = 28;
Steven Liu4bf01bc2014-07-17 11:05:29 -0500117 private static final int CMD_INVOKE_OEM_RIL_REQUEST_RAW = 29;
118 private static final int EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE = 30;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700119
120 /** The singleton instance. */
121 private static PhoneInterfaceManager sInstance;
122
123 PhoneGlobals mApp;
124 Phone mPhone;
125 CallManager mCM;
126 AppOpsManager mAppOps;
127 MainThreadHandler mMainThreadHandler;
128
129 /**
Derek Tan89e89d42014-07-08 17:00:10 -0700130 * Indicates if Android should display a simplified Mobile Network Settings UI in a specific
131 * subscription.
132 */
133 Set<Long> mSimplifiedNetworkSettings;
Derek Tan7226c842014-07-02 17:42:23 -0700134 Map<Long, AdnRecord> mAdnRecordsForDisplay;
Derek Tan89e89d42014-07-08 17:00:10 -0700135
136 /**
Shishir Agrawal566b7612013-10-28 14:41:00 -0700137 * A request object to use for transmitting data to an ICC.
138 */
139 private static final class IccAPDUArgument {
140 public int channel, cla, command, p1, p2, p3;
141 public String data;
142
143 public IccAPDUArgument(int channel, int cla, int command,
144 int p1, int p2, int p3, String data) {
145 this.channel = channel;
146 this.cla = cla;
147 this.command = command;
148 this.p1 = p1;
149 this.p2 = p2;
150 this.p3 = p3;
151 this.data = data;
152 }
153 }
154
155 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700156 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
157 * request after sending. The main thread will notify the request when it is complete.
158 */
159 private static final class MainThreadRequest {
160 /** The argument to use for the request */
161 public Object argument;
162 /** The result of the request that is run on the main thread */
163 public Object result;
164
165 public MainThreadRequest(Object argument) {
166 this.argument = argument;
167 }
168 }
169
Sailesh Nepalcc0375f2013-11-13 09:15:18 -0800170 private static final class IncomingThirdPartyCallArgs {
171 public final ComponentName component;
172 public final String callId;
173 public final String callerDisplayName;
174
175 public IncomingThirdPartyCallArgs(ComponentName component, String callId,
176 String callerDisplayName) {
177 this.component = component;
178 this.callId = callId;
179 this.callerDisplayName = callerDisplayName;
180 }
181 }
182
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700183 /**
184 * A handler that processes messages on the main thread in the phone process. Since many
185 * of the Phone calls are not thread safe this is needed to shuttle the requests from the
186 * inbound binder threads to the main thread in the phone process. The Binder thread
187 * may provide a {@link MainThreadRequest} object in the msg.obj field that they are waiting
188 * on, which will be notified when the operation completes and will contain the result of the
189 * request.
190 *
191 * <p>If a MainThreadRequest object is provided in the msg.obj field,
192 * note that request.result must be set to something non-null for the calling thread to
193 * unblock.
194 */
195 private final class MainThreadHandler extends Handler {
196 @Override
197 public void handleMessage(Message msg) {
198 MainThreadRequest request;
199 Message onCompleted;
200 AsyncResult ar;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700201 UiccCard uiccCard = UiccController.getInstance().getUiccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700202
203 switch (msg.what) {
204 case CMD_HANDLE_PIN_MMI:
205 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800206 request.result = mPhone.handlePinMmi((String) request.argument);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700207 // Wake up the requesting thread
208 synchronized (request) {
209 request.notifyAll();
210 }
211 break;
212
213 case CMD_HANDLE_NEIGHBORING_CELL:
214 request = (MainThreadRequest) msg.obj;
215 onCompleted = obtainMessage(EVENT_NEIGHBORING_CELL_DONE,
216 request);
217 mPhone.getNeighboringCids(onCompleted);
218 break;
219
220 case EVENT_NEIGHBORING_CELL_DONE:
221 ar = (AsyncResult) msg.obj;
222 request = (MainThreadRequest) ar.userObj;
223 if (ar.exception == null && ar.result != null) {
224 request.result = ar.result;
225 } else {
226 // create an empty list to notify the waiting thread
Jake Hambye994d462014-02-03 13:10:13 -0800227 request.result = new ArrayList<NeighboringCellInfo>(0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700228 }
229 // Wake up the requesting thread
230 synchronized (request) {
231 request.notifyAll();
232 }
233 break;
234
235 case CMD_ANSWER_RINGING_CALL:
236 answerRingingCallInternal();
237 break;
238
239 case CMD_SILENCE_RINGER:
240 silenceRingerInternal();
241 break;
242
243 case CMD_END_CALL:
244 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800245 boolean hungUp;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700246 int phoneType = mPhone.getPhoneType();
247 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
248 // CDMA: If the user presses the Power button we treat it as
249 // ending the complete call session
250 hungUp = PhoneUtils.hangupRingingAndActive(mPhone);
251 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
252 // GSM: End the call as per the Phone state
253 hungUp = PhoneUtils.hangup(mCM);
254 } else {
255 throw new IllegalStateException("Unexpected phone type: " + phoneType);
256 }
257 if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up"));
258 request.result = hungUp;
259 // Wake up the requesting thread
260 synchronized (request) {
261 request.notifyAll();
262 }
263 break;
264
Shishir Agrawal566b7612013-10-28 14:41:00 -0700265 case CMD_TRANSMIT_APDU:
266 request = (MainThreadRequest) msg.obj;
267 IccAPDUArgument argument = (IccAPDUArgument) request.argument;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700268 if (uiccCard == null) {
269 loge("iccTransmitApduLogicalChannel: No UICC");
270 request.result = new IccIoResult(0x6F, 0, (byte[])null);
271 synchronized (request) {
272 request.notifyAll();
273 }
274 } else {
275 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_DONE, request);
276 uiccCard.iccTransmitApduLogicalChannel(
Shishir Agrawal566b7612013-10-28 14:41:00 -0700277 argument.channel, argument.cla, argument.command,
278 argument.p1, argument.p2, argument.p3, argument.data,
279 onCompleted);
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700280 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700281 break;
282
283 case EVENT_TRANSMIT_APDU_DONE:
284 ar = (AsyncResult) msg.obj;
285 request = (MainThreadRequest) ar.userObj;
286 if (ar.exception == null && ar.result != null) {
287 request.result = ar.result;
288 } else {
289 request.result = new IccIoResult(0x6F, 0, (byte[])null);
290 if (ar.result == null) {
291 loge("iccTransmitApduLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800292 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700293 loge("iccTransmitApduLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800294 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700295 } else {
296 loge("iccTransmitApduLogicalChannel: Unknown exception");
297 }
298 }
299 synchronized (request) {
300 request.notifyAll();
301 }
302 break;
303
Derek Tan4d5e5c12014-02-04 11:54:58 -0800304 case CMD_SEND_ENVELOPE:
305 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700306 if (uiccCard == null) {
307 loge("sendEnvelopeWithStatus: No UICC");
308 request.result = new IccIoResult(0x6F, 0, (byte[])null);
309 synchronized (request) {
310 request.notifyAll();
311 }
312 } else {
313 onCompleted = obtainMessage(EVENT_SEND_ENVELOPE_DONE, request);
314 uiccCard.sendEnvelopeWithStatus((String)request.argument, onCompleted);
315 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800316 break;
317
318 case EVENT_SEND_ENVELOPE_DONE:
319 ar = (AsyncResult) msg.obj;
320 request = (MainThreadRequest) ar.userObj;
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700321 if (ar.exception == null && ar.result != null) {
322 request.result = ar.result;
Derek Tan4d5e5c12014-02-04 11:54:58 -0800323 } else {
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700324 request.result = new IccIoResult(0x6F, 0, (byte[])null);
325 if (ar.result == null) {
326 loge("sendEnvelopeWithStatus: Empty response");
327 } else if (ar.exception instanceof CommandException) {
328 loge("sendEnvelopeWithStatus: CommandException: " +
329 ar.exception);
330 } else {
331 loge("sendEnvelopeWithStatus: exception:" + ar.exception);
332 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800333 }
334 synchronized (request) {
335 request.notifyAll();
336 }
337 break;
338
Shishir Agrawal566b7612013-10-28 14:41:00 -0700339 case CMD_OPEN_CHANNEL:
340 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700341 if (uiccCard == null) {
342 loge("iccOpenLogicalChannel: No UICC");
343 request.result = new IccIoResult(0x6F, 0, (byte[])null);
344 synchronized (request) {
345 request.notifyAll();
346 }
347 } else {
348 onCompleted = obtainMessage(EVENT_OPEN_CHANNEL_DONE, request);
349 uiccCard.iccOpenLogicalChannel((String)request.argument, onCompleted);
350 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700351 break;
352
353 case EVENT_OPEN_CHANNEL_DONE:
354 ar = (AsyncResult) msg.obj;
355 request = (MainThreadRequest) ar.userObj;
356 if (ar.exception == null && ar.result != null) {
Jake Hambye994d462014-02-03 13:10:13 -0800357 request.result = ((int[]) ar.result)[0];
Shishir Agrawal566b7612013-10-28 14:41:00 -0700358 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800359 request.result = -1;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700360 if (ar.result == null) {
361 loge("iccOpenLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800362 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700363 loge("iccOpenLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800364 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700365 } else {
366 loge("iccOpenLogicalChannel: Unknown exception");
367 }
368 }
369 synchronized (request) {
370 request.notifyAll();
371 }
372 break;
373
374 case CMD_CLOSE_CHANNEL:
375 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700376 if (uiccCard == null) {
377 loge("iccCloseLogicalChannel: No UICC");
378 request.result = new IccIoResult(0x6F, 0, (byte[])null);
379 synchronized (request) {
380 request.notifyAll();
381 }
382 } else {
383 onCompleted = obtainMessage(EVENT_CLOSE_CHANNEL_DONE, request);
384 uiccCard.iccCloseLogicalChannel((Integer) request.argument, onCompleted);
385 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700386 break;
387
388 case EVENT_CLOSE_CHANNEL_DONE:
Jake Hambye994d462014-02-03 13:10:13 -0800389 handleNullReturnEvent(msg, "iccCloseLogicalChannel");
390 break;
391
392 case CMD_NV_READ_ITEM:
393 request = (MainThreadRequest) msg.obj;
394 onCompleted = obtainMessage(EVENT_NV_READ_ITEM_DONE, request);
395 mPhone.nvReadItem((Integer) request.argument, onCompleted);
396 break;
397
398 case EVENT_NV_READ_ITEM_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700399 ar = (AsyncResult) msg.obj;
400 request = (MainThreadRequest) ar.userObj;
Jake Hambye994d462014-02-03 13:10:13 -0800401 if (ar.exception == null && ar.result != null) {
402 request.result = ar.result; // String
Shishir Agrawal566b7612013-10-28 14:41:00 -0700403 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800404 request.result = "";
405 if (ar.result == null) {
406 loge("nvReadItem: Empty response");
407 } else if (ar.exception instanceof CommandException) {
408 loge("nvReadItem: CommandException: " +
409 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700410 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800411 loge("nvReadItem: Unknown exception");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700412 }
413 }
414 synchronized (request) {
415 request.notifyAll();
416 }
417 break;
418
Jake Hambye994d462014-02-03 13:10:13 -0800419 case CMD_NV_WRITE_ITEM:
420 request = (MainThreadRequest) msg.obj;
421 onCompleted = obtainMessage(EVENT_NV_WRITE_ITEM_DONE, request);
422 Pair<Integer, String> idValue = (Pair<Integer, String>) request.argument;
423 mPhone.nvWriteItem(idValue.first, idValue.second, onCompleted);
424 break;
425
426 case EVENT_NV_WRITE_ITEM_DONE:
427 handleNullReturnEvent(msg, "nvWriteItem");
428 break;
429
430 case CMD_NV_WRITE_CDMA_PRL:
431 request = (MainThreadRequest) msg.obj;
432 onCompleted = obtainMessage(EVENT_NV_WRITE_CDMA_PRL_DONE, request);
433 mPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
434 break;
435
436 case EVENT_NV_WRITE_CDMA_PRL_DONE:
437 handleNullReturnEvent(msg, "nvWriteCdmaPrl");
438 break;
439
440 case CMD_NV_RESET_CONFIG:
441 request = (MainThreadRequest) msg.obj;
442 onCompleted = obtainMessage(EVENT_NV_RESET_CONFIG_DONE, request);
443 mPhone.nvResetConfig((Integer) request.argument, onCompleted);
444 break;
445
446 case EVENT_NV_RESET_CONFIG_DONE:
447 handleNullReturnEvent(msg, "nvResetConfig");
448 break;
449
Jake Hamby7c27be32014-03-03 13:25:59 -0800450 case CMD_GET_PREFERRED_NETWORK_TYPE:
451 request = (MainThreadRequest) msg.obj;
452 onCompleted = obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE_DONE, request);
453 mPhone.getPreferredNetworkType(onCompleted);
454 break;
455
456 case EVENT_GET_PREFERRED_NETWORK_TYPE_DONE:
457 ar = (AsyncResult) msg.obj;
458 request = (MainThreadRequest) ar.userObj;
459 if (ar.exception == null && ar.result != null) {
460 request.result = ar.result; // Integer
461 } else {
462 request.result = -1;
463 if (ar.result == null) {
464 loge("getPreferredNetworkType: Empty response");
465 } else if (ar.exception instanceof CommandException) {
466 loge("getPreferredNetworkType: CommandException: " +
467 ar.exception);
468 } else {
469 loge("getPreferredNetworkType: Unknown exception");
470 }
471 }
472 synchronized (request) {
473 request.notifyAll();
474 }
475 break;
476
477 case CMD_SET_PREFERRED_NETWORK_TYPE:
478 request = (MainThreadRequest) msg.obj;
479 onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);
480 int networkType = (Integer) request.argument;
481 mPhone.setPreferredNetworkType(networkType, onCompleted);
482 break;
483
484 case EVENT_SET_PREFERRED_NETWORK_TYPE_DONE:
485 handleNullReturnEvent(msg, "setPreferredNetworkType");
486 break;
487
Junda Liu787bc7e2014-06-30 13:38:02 -0700488 case CMD_SET_CDMA_SUBSCRIPTION:
489 request = (MainThreadRequest) msg.obj;
490 onCompleted = obtainMessage(EVENT_SET_CDMA_SUBSCRIPTION_DONE, request);
491 int subscriptionType = (Integer) request.argument;
492 mPhone.setCdmaSubscription(subscriptionType, onCompleted);
493 break;
494
495 case EVENT_SET_CDMA_SUBSCRIPTION_DONE:
496 handleNullReturnEvent(msg, "setCdmaSubscription");
497 break;
498
Steven Liu4bf01bc2014-07-17 11:05:29 -0500499 case CMD_INVOKE_OEM_RIL_REQUEST_RAW:
500 request = (MainThreadRequest)msg.obj;
501 onCompleted = obtainMessage(EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE, request);
502 mPhone.invokeOemRilRequestRaw((byte[])request.argument, onCompleted);
503 break;
504
505 case EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE:
506 ar = (AsyncResult)msg.obj;
507 request = (MainThreadRequest)ar.userObj;
508 request.result = ar;
509 synchronized (request) {
510 request.notifyAll();
511 }
512 break;
513
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700514 default:
515 Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
516 break;
517 }
518 }
Jake Hambye994d462014-02-03 13:10:13 -0800519
520 private void handleNullReturnEvent(Message msg, String command) {
521 AsyncResult ar = (AsyncResult) msg.obj;
522 MainThreadRequest request = (MainThreadRequest) ar.userObj;
523 if (ar.exception == null) {
524 request.result = true;
525 } else {
526 request.result = false;
527 if (ar.exception instanceof CommandException) {
528 loge(command + ": CommandException: " + ar.exception);
529 } else {
530 loge(command + ": Unknown exception");
531 }
532 }
533 synchronized (request) {
534 request.notifyAll();
535 }
536 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700537 }
538
539 /**
540 * Posts the specified command to be executed on the main thread,
541 * waits for the request to complete, and returns the result.
542 * @see #sendRequestAsync
543 */
544 private Object sendRequest(int command, Object argument) {
Santos Cordon500b0e02014-06-17 10:33:33 -0700545 return sendRequest(command, argument, null);
Wink Saville36469e72014-06-11 15:17:00 -0700546 }
547
548 /**
549 * Posts the specified command to be executed on the main thread,
550 * waits for the request to complete, and returns the result.
551 * @see #sendRequestAsync
552 */
553 private Object sendRequest(int command, Object argument, Object argument2) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700554 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
555 throw new RuntimeException("This method will deadlock if called from the main thread.");
556 }
557
558 MainThreadRequest request = new MainThreadRequest(argument);
559 Message msg = mMainThreadHandler.obtainMessage(command, request);
560 msg.sendToTarget();
561
562 // Wait for the request to complete
563 synchronized (request) {
564 while (request.result == null) {
565 try {
566 request.wait();
567 } catch (InterruptedException e) {
568 // Do nothing, go back and wait until the request is complete
569 }
570 }
571 }
572 return request.result;
573 }
574
575 /**
576 * Asynchronous ("fire and forget") version of sendRequest():
577 * Posts the specified command to be executed on the main thread, and
578 * returns immediately.
579 * @see #sendRequest
580 */
581 private void sendRequestAsync(int command) {
582 mMainThreadHandler.sendEmptyMessage(command);
583 }
584
585 /**
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -0700586 * Same as {@link #sendRequestAsync(int)} except it takes an argument.
587 * @see {@link #sendRequest(int,Object)}
588 */
589 private void sendRequestAsync(int command, Object argument) {
590 MainThreadRequest request = new MainThreadRequest(argument);
591 Message msg = mMainThreadHandler.obtainMessage(command, request);
592 msg.sendToTarget();
593 }
594
595 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700596 * Initialize the singleton PhoneInterfaceManager instance.
597 * This is only done once, at startup, from PhoneApp.onCreate().
598 */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700599 /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700600 synchronized (PhoneInterfaceManager.class) {
601 if (sInstance == null) {
Sailesh Nepal194161e2014-07-03 08:57:44 -0700602 sInstance = new PhoneInterfaceManager(app, phone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700603 } else {
604 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
605 }
606 return sInstance;
607 }
608 }
609
610 /** Private constructor; @see init() */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700611 private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700612 mApp = app;
613 mPhone = phone;
614 mCM = PhoneGlobals.getInstance().mCM;
Derek Tan89e89d42014-07-08 17:00:10 -0700615 mSimplifiedNetworkSettings = new HashSet<Long>();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700616 mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
617 mMainThreadHandler = new MainThreadHandler();
Derek Tan7226c842014-07-02 17:42:23 -0700618 mAdnRecordsForDisplay = new HashMap<Long, AdnRecord>();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700619 publish();
620 }
621
622 private void publish() {
623 if (DBG) log("publish: " + this);
624
625 ServiceManager.addService("phone", this);
626 }
627
Wink Saville36469e72014-06-11 15:17:00 -0700628 // returns phone associated with the subId.
629 // getPhone(0) returns default phone in single SIM mode.
630 private Phone getPhone(long subId) {
631 // FIXME: hack for the moment
632 return mPhone;
633 // return PhoneUtils.getPhoneUsingSubId(subId);
634 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700635 //
636 // Implementation of the ITelephony interface.
637 //
638
639 public void dial(String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700640 dialUsingSubId(getPreferredVoiceSubscription(), number);
641 }
642
643 public void dialUsingSubId(long subId, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700644 if (DBG) log("dial: " + number);
645 // No permission check needed here: This is just a wrapper around the
646 // ACTION_DIAL intent, which is available to any app since it puts up
647 // the UI before it does anything.
648
649 String url = createTelUrl(number);
650 if (url == null) {
651 return;
652 }
653
654 // PENDING: should we just silently fail if phone is offhook or ringing?
Wink Saville36469e72014-06-11 15:17:00 -0700655 PhoneConstants.State state = mCM.getState(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700656 if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
657 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
658 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Wink Saville36469e72014-06-11 15:17:00 -0700659 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700660 mApp.startActivity(intent);
661 }
662 }
663
664 public void call(String callingPackage, String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700665 callUsingSubId(getPreferredVoiceSubscription(), callingPackage, number);
666 }
667
668 public void callUsingSubId(long subId, String callingPackage, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700669 if (DBG) log("call: " + number);
670
671 // This is just a wrapper around the ACTION_CALL intent, but we still
672 // need to do a permission check since we're calling startActivity()
673 // from the context of the phone app.
674 enforceCallPermission();
675
676 if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
677 != AppOpsManager.MODE_ALLOWED) {
678 return;
679 }
680
681 String url = createTelUrl(number);
682 if (url == null) {
683 return;
684 }
685
686 Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
Wink Saville36469e72014-06-11 15:17:00 -0700687 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700688 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
689 mApp.startActivity(intent);
690 }
691
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700692 /**
693 * End a call based on call state
694 * @return true is a call was ended
695 */
696 public boolean endCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700697 return endCallUsingSubId(getDefaultSubscription());
698 }
699
700 /**
701 * End a call based on the call state of the subId
702 * @return true is a call was ended
703 */
704 public boolean endCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700705 enforceCallPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700706 return (Boolean) sendRequest(CMD_END_CALL, subId, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700707 }
708
709 public void answerRingingCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700710 answerRingingCallUsingSubId(getDefaultSubscription());
711 }
712
713 public void answerRingingCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700714 if (DBG) log("answerRingingCall...");
715 // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
716 // but that can probably wait till the big TelephonyManager API overhaul.
717 // For now, protect this call with the MODIFY_PHONE_STATE permission.
718 enforceModifyPermission();
719 sendRequestAsync(CMD_ANSWER_RINGING_CALL);
720 }
721
722 /**
723 * Make the actual telephony calls to implement answerRingingCall().
724 * This should only be called from the main thread of the Phone app.
725 * @see #answerRingingCall
726 *
727 * TODO: it would be nice to return true if we answered the call, or
728 * false if there wasn't actually a ringing incoming call, or some
729 * other error occurred. (In other words, pass back the return value
730 * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
731 * But that would require calling this method via sendRequest() rather
732 * than sendRequestAsync(), and right now we don't actually *need* that
733 * return value, so let's just return void for now.
734 */
735 private void answerRingingCallInternal() {
736 final boolean hasRingingCall = !mPhone.getRingingCall().isIdle();
737 if (hasRingingCall) {
738 final boolean hasActiveCall = !mPhone.getForegroundCall().isIdle();
739 final boolean hasHoldingCall = !mPhone.getBackgroundCall().isIdle();
740 if (hasActiveCall && hasHoldingCall) {
741 // Both lines are in use!
742 // TODO: provide a flag to let the caller specify what
743 // policy to use if both lines are in use. (The current
744 // behavior is hardwired to "answer incoming, end ongoing",
745 // which is how the CALL button is specced to behave.)
746 PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
747 return;
748 } else {
749 // answerCall() will automatically hold the current active
750 // call, if there is one.
751 PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
752 return;
753 }
754 } else {
755 // No call was ringing.
756 return;
757 }
758 }
759
760 public void silenceRinger() {
761 if (DBG) log("silenceRinger...");
762 // TODO: find a more appropriate permission to check here.
763 // (That can probably wait till the big TelephonyManager API overhaul.
764 // For now, protect this call with the MODIFY_PHONE_STATE permission.)
765 enforceModifyPermission();
766 sendRequestAsync(CMD_SILENCE_RINGER);
767 }
768
769 /**
770 * Internal implemenation of silenceRinger().
771 * This should only be called from the main thread of the Phone app.
772 * @see #silenceRinger
773 */
774 private void silenceRingerInternal() {
775 if ((mCM.getState() == PhoneConstants.State.RINGING)
776 && mApp.notifier.isRinging()) {
777 // Ringer is actually playing, so silence it.
778 if (DBG) log("silenceRingerInternal: silencing...");
779 mApp.notifier.silenceRinger();
780 }
781 }
782
783 public boolean isOffhook() {
Wink Saville36469e72014-06-11 15:17:00 -0700784 return isOffhookUsingSubId(getDefaultSubscription());
785 }
786
787 public boolean isOffhookUsingSubId(long subId) {
788 return (getPhone(subId).getState() == PhoneConstants.State.OFFHOOK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700789 }
790
791 public boolean isRinging() {
Wink Saville36469e72014-06-11 15:17:00 -0700792 return (isRingingUsingSubId(getDefaultSubscription()));
793 }
794
795 public boolean isRingingUsingSubId(long subId) {
796 return (getPhone(subId).getState() == PhoneConstants.State.RINGING);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700797 }
798
799 public boolean isIdle() {
Wink Saville36469e72014-06-11 15:17:00 -0700800 return isIdleUsingSubId(getDefaultSubscription());
801 }
802
803 public boolean isIdleUsingSubId(long subId) {
804 return (getPhone(subId).getState() == PhoneConstants.State.IDLE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700805 }
806
807 public boolean isSimPinEnabled() {
808 enforceReadPermission();
809 return (PhoneGlobals.getInstance().isSimPinEnabled());
810 }
811
812 public boolean supplyPin(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700813 return supplyPinUsingSubId(getDefaultSubscription(), pin);
814 }
815
816 public boolean supplyPinUsingSubId(long subId, String pin) {
817 int [] resultArray = supplyPinReportResultUsingSubId(subId, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700818 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
819 }
820
821 public boolean supplyPuk(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700822 return supplyPukUsingSubId(getDefaultSubscription(), puk, pin);
823 }
824
825 public boolean supplyPukUsingSubId(long subId, String puk, String pin) {
826 int [] resultArray = supplyPukReportResultUsingSubId(subId, puk, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700827 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
828 }
829
830 /** {@hide} */
831 public int[] supplyPinReportResult(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700832 return supplyPinReportResultUsingSubId(getDefaultSubscription(), pin);
833 }
834
835 public int[] supplyPinReportResultUsingSubId(long subId, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700836 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700837 final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700838 checkSimPin.start();
839 return checkSimPin.unlockSim(null, pin);
840 }
841
Wink Saville9de0f752013-10-22 19:04:03 -0700842 /** {@hide} */
843 public int[] supplyPukReportResult(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700844 return supplyPukReportResultUsingSubId(getDefaultSubscription(), puk, pin);
845 }
846
847 public int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700848 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700849 final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700850 checkSimPuk.start();
851 return checkSimPuk.unlockSim(puk, pin);
852 }
853
854 /**
Wink Saville9de0f752013-10-22 19:04:03 -0700855 * Helper thread to turn async call to SimCard#supplyPin into
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700856 * a synchronous one.
857 */
858 private static class UnlockSim extends Thread {
859
860 private final IccCard mSimCard;
861
862 private boolean mDone = false;
Wink Saville9de0f752013-10-22 19:04:03 -0700863 private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
864 private int mRetryCount = -1;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700865
866 // For replies from SimCard interface
867 private Handler mHandler;
868
869 // For async handler to identify request type
870 private static final int SUPPLY_PIN_COMPLETE = 100;
871
872 public UnlockSim(IccCard simCard) {
873 mSimCard = simCard;
874 }
875
876 @Override
877 public void run() {
878 Looper.prepare();
879 synchronized (UnlockSim.this) {
880 mHandler = new Handler() {
881 @Override
882 public void handleMessage(Message msg) {
883 AsyncResult ar = (AsyncResult) msg.obj;
884 switch (msg.what) {
885 case SUPPLY_PIN_COMPLETE:
886 Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
887 synchronized (UnlockSim.this) {
Wink Saville9de0f752013-10-22 19:04:03 -0700888 mRetryCount = msg.arg1;
889 if (ar.exception != null) {
890 if (ar.exception instanceof CommandException &&
891 ((CommandException)(ar.exception)).getCommandError()
892 == CommandException.Error.PASSWORD_INCORRECT) {
893 mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
894 } else {
895 mResult = PhoneConstants.PIN_GENERAL_FAILURE;
896 }
897 } else {
898 mResult = PhoneConstants.PIN_RESULT_SUCCESS;
899 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700900 mDone = true;
901 UnlockSim.this.notifyAll();
902 }
903 break;
904 }
905 }
906 };
907 UnlockSim.this.notifyAll();
908 }
909 Looper.loop();
910 }
911
912 /*
913 * Use PIN or PUK to unlock SIM card
914 *
915 * If PUK is null, unlock SIM card with PIN
916 *
917 * If PUK is not null, unlock SIM card with PUK and set PIN code
918 */
Wink Saville9de0f752013-10-22 19:04:03 -0700919 synchronized int[] unlockSim(String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700920
921 while (mHandler == null) {
922 try {
923 wait();
924 } catch (InterruptedException e) {
925 Thread.currentThread().interrupt();
926 }
927 }
928 Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
929
930 if (puk == null) {
931 mSimCard.supplyPin(pin, callback);
932 } else {
933 mSimCard.supplyPuk(puk, pin, callback);
934 }
935
936 while (!mDone) {
937 try {
938 Log.d(LOG_TAG, "wait for done");
939 wait();
940 } catch (InterruptedException e) {
941 // Restore the interrupted status
942 Thread.currentThread().interrupt();
943 }
944 }
945 Log.d(LOG_TAG, "done");
Wink Saville9de0f752013-10-22 19:04:03 -0700946 int[] resultArray = new int[2];
947 resultArray[0] = mResult;
948 resultArray[1] = mRetryCount;
949 return resultArray;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700950 }
951 }
952
953 public void updateServiceLocation() {
Wink Saville36469e72014-06-11 15:17:00 -0700954 updateServiceLocationUsingSubId(getDefaultSubscription());
955
956 }
957
958 public void updateServiceLocationUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700959 // No permission check needed here: this call is harmless, and it's
960 // needed for the ServiceState.requestStateUpdate() call (which is
961 // already intentionally exposed to 3rd parties.)
Wink Saville36469e72014-06-11 15:17:00 -0700962 getPhone(subId).updateServiceLocation();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700963 }
964
965 public boolean isRadioOn() {
Wink Saville36469e72014-06-11 15:17:00 -0700966 return isRadioOnUsingSubId(getDefaultSubscription());
967 }
968
969 public boolean isRadioOnUsingSubId(long subId) {
970 return getPhone(subId).getServiceState().getState() != ServiceState.STATE_POWER_OFF;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700971 }
972
973 public void toggleRadioOnOff() {
Wink Saville36469e72014-06-11 15:17:00 -0700974 toggleRadioOnOffUsingSubId(getDefaultSubscription());
975
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700976 }
Wink Saville36469e72014-06-11 15:17:00 -0700977
978 public void toggleRadioOnOffUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700979 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700980 getPhone(subId).setRadioPower(!isRadioOnUsingSubId(subId));
981 }
982
983 public boolean setRadio(boolean turnOn) {
984 return setRadioUsingSubId(getDefaultSubscription(), turnOn);
985 }
986
987 public boolean setRadioUsingSubId(long subId, boolean turnOn) {
988 enforceModifyPermission();
989 if ((getPhone(subId).getServiceState().getState() !=
990 ServiceState.STATE_POWER_OFF) != turnOn) {
991 toggleRadioOnOffUsingSubId(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700992 }
993 return true;
994 }
Wink Saville36469e72014-06-11 15:17:00 -0700995
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700996 public boolean setRadioPower(boolean turnOn) {
Wink Saville36469e72014-06-11 15:17:00 -0700997 return setRadioPowerUsingSubId(getDefaultSubscription(), turnOn);
998 }
999
1000 public boolean setRadioPowerUsingSubId(long subId, boolean turnOn) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001001 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001002 getPhone(subId).setRadioPower(turnOn);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001003 return true;
1004 }
1005
Wink Saville36469e72014-06-11 15:17:00 -07001006 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001007 public boolean enableDataConnectivity() {
1008 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001009 long subId = SubscriptionManager.getDefaultDataSubId();
1010 getPhone(subId).setDataEnabled(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001011 return true;
1012 }
1013
Wink Saville36469e72014-06-11 15:17:00 -07001014 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001015 public boolean disableDataConnectivity() {
1016 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001017 long subId = SubscriptionManager.getDefaultDataSubId();
1018 getPhone(subId).setDataEnabled(false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001019 return true;
1020 }
1021
Wink Saville36469e72014-06-11 15:17:00 -07001022 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001023 public boolean isDataConnectivityPossible() {
Wink Saville36469e72014-06-11 15:17:00 -07001024 long subId = SubscriptionManager.getDefaultDataSubId();
1025 return getPhone(subId).isDataConnectivityPossible();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001026 }
1027
1028 public boolean handlePinMmi(String dialString) {
Wink Saville36469e72014-06-11 15:17:00 -07001029 return handlePinMmiUsingSubId(getDefaultSubscription(), dialString);
1030 }
1031
1032 public boolean handlePinMmiUsingSubId(long subId, String dialString) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001033 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001034 return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001035 }
1036
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001037 public int getCallState() {
Wink Saville36469e72014-06-11 15:17:00 -07001038 return getCallStateUsingSubId(getDefaultSubscription());
1039 }
1040
1041 public int getCallStateUsingSubId(long subId) {
1042 return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001043 }
1044
1045 public int getDataState() {
Wink Saville36469e72014-06-11 15:17:00 -07001046 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1047 return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001048 }
1049
1050 public int getDataActivity() {
Wink Saville36469e72014-06-11 15:17:00 -07001051 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1052 return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001053 }
1054
1055 @Override
1056 public Bundle getCellLocation() {
1057 try {
1058 mApp.enforceCallingOrSelfPermission(
1059 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1060 } catch (SecurityException e) {
1061 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1062 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1063 // is the weaker precondition
1064 mApp.enforceCallingOrSelfPermission(
1065 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1066 }
1067
Jake Hambye994d462014-02-03 13:10:13 -08001068 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001069 if (DBG_LOC) log("getCellLocation: is active user");
1070 Bundle data = new Bundle();
1071 mPhone.getCellLocation().fillInNotifierBundle(data);
1072 return data;
1073 } else {
1074 if (DBG_LOC) log("getCellLocation: suppress non-active user");
1075 return null;
1076 }
1077 }
1078
1079 @Override
1080 public void enableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001081 enableLocationUpdatesUsingSubId(getDefaultSubscription());
1082 }
1083
1084 public void enableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001085 mApp.enforceCallingOrSelfPermission(
1086 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001087 getPhone(subId).enableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001088 }
1089
1090 @Override
1091 public void disableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001092 disableLocationUpdatesUsingSubId(getDefaultSubscription());
1093 }
1094
1095 public void disableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001096 mApp.enforceCallingOrSelfPermission(
1097 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001098 getPhone(subId).disableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001099 }
1100
1101 @Override
1102 @SuppressWarnings("unchecked")
1103 public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1104 try {
1105 mApp.enforceCallingOrSelfPermission(
1106 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1107 } catch (SecurityException e) {
1108 // If we have ACCESS_FINE_LOCATION permission, skip the check
1109 // for ACCESS_COARSE_LOCATION
1110 // A failure should throw the SecurityException from
1111 // ACCESS_COARSE_LOCATION since this is the weaker precondition
1112 mApp.enforceCallingOrSelfPermission(
1113 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1114 }
1115
1116 if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1117 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1118 return null;
1119 }
Jake Hambye994d462014-02-03 13:10:13 -08001120 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001121 if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1122
1123 ArrayList<NeighboringCellInfo> cells = null;
1124
1125 try {
1126 cells = (ArrayList<NeighboringCellInfo>) sendRequest(
Wink Saville36469e72014-06-11 15:17:00 -07001127 CMD_HANDLE_NEIGHBORING_CELL, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001128 } catch (RuntimeException e) {
Wink Saville36469e72014-06-11 15:17:00 -07001129 Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001130 }
1131 return cells;
1132 } else {
1133 if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1134 return null;
1135 }
1136 }
1137
1138
1139 @Override
1140 public List<CellInfo> getAllCellInfo() {
1141 try {
1142 mApp.enforceCallingOrSelfPermission(
1143 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1144 } catch (SecurityException e) {
1145 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1146 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1147 // is the weaker precondition
1148 mApp.enforceCallingOrSelfPermission(
1149 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1150 }
1151
Jake Hambye994d462014-02-03 13:10:13 -08001152 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001153 if (DBG_LOC) log("getAllCellInfo: is active user");
1154 return mPhone.getAllCellInfo();
1155 } else {
1156 if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1157 return null;
1158 }
1159 }
1160
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -07001161 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001162 public void setCellInfoListRate(int rateInMillis) {
1163 mPhone.setCellInfoListRate(rateInMillis);
1164 }
1165
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001166 //
1167 // Internal helper methods.
1168 //
1169
Jake Hambye994d462014-02-03 13:10:13 -08001170 private static boolean checkIfCallerIsSelfOrForegroundUser() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001171 boolean ok;
1172
1173 boolean self = Binder.getCallingUid() == Process.myUid();
1174 if (!self) {
1175 // Get the caller's user id then clear the calling identity
1176 // which will be restored in the finally clause.
1177 int callingUser = UserHandle.getCallingUserId();
1178 long ident = Binder.clearCallingIdentity();
1179
1180 try {
1181 // With calling identity cleared the current user is the foreground user.
1182 int foregroundUser = ActivityManager.getCurrentUser();
1183 ok = (foregroundUser == callingUser);
1184 if (DBG_LOC) {
1185 log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1186 + " callingUser=" + callingUser + " ok=" + ok);
1187 }
1188 } catch (Exception ex) {
1189 if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1190 ok = false;
1191 } finally {
1192 Binder.restoreCallingIdentity(ident);
1193 }
1194 } else {
1195 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1196 ok = true;
1197 }
1198 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1199 return ok;
1200 }
1201
1202 /**
1203 * Make sure the caller has the READ_PHONE_STATE permission.
1204 *
1205 * @throws SecurityException if the caller does not have the required permission
1206 */
1207 private void enforceReadPermission() {
1208 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
1209 }
1210
1211 /**
1212 * Make sure the caller has the MODIFY_PHONE_STATE permission.
1213 *
1214 * @throws SecurityException if the caller does not have the required permission
1215 */
1216 private void enforceModifyPermission() {
1217 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1218 }
1219
1220 /**
Junda Liua2e36012014-07-09 18:30:01 -07001221 * Make sure either system app or the caller has carrier privilege.
1222 *
1223 * @throws SecurityException if the caller does not have the required permission/privilege
1224 */
1225 private void enforceModifyPermissionOrCarrierPrivilege() {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001226 int permission = mApp.checkCallingOrSelfPermission(
1227 android.Manifest.permission.MODIFY_PHONE_STATE);
1228 if (permission == PackageManager.PERMISSION_GRANTED) {
1229 return;
1230 }
1231
1232 log("No modify permission, check carrier privilege next.");
1233 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1234 loge("No Carrier Privilege.");
1235 throw new SecurityException("No modify permission or carrier privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001236 }
1237 }
1238
1239 /**
1240 * Make sure the caller has carrier privilege.
1241 *
1242 * @throws SecurityException if the caller does not have the required permission
1243 */
1244 private void enforceCarrierPrivilege() {
1245 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001246 loge("No Carrier Privilege.");
1247 throw new SecurityException("No Carrier Privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001248 }
1249 }
1250
1251 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001252 * Make sure the caller has the CALL_PHONE permission.
1253 *
1254 * @throws SecurityException if the caller does not have the required permission
1255 */
1256 private void enforceCallPermission() {
1257 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1258 }
1259
Shishir Agrawal566b7612013-10-28 14:41:00 -07001260 /**
Gabriel Peal36ebb0d2014-03-20 09:20:43 -07001261 * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1262 *
1263 * @throws SecurityException if the caller does not have the required permission
1264 */
1265 private void enforcePrivilegedPhoneStatePermission() {
1266 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1267 null);
1268 }
1269
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001270 private String createTelUrl(String number) {
1271 if (TextUtils.isEmpty(number)) {
1272 return null;
1273 }
1274
Jake Hambye994d462014-02-03 13:10:13 -08001275 return "tel:" + number;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001276 }
1277
Ihab Awadf9e92732013-12-05 18:02:52 -08001278 private static void log(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001279 Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1280 }
1281
Ihab Awadf9e92732013-12-05 18:02:52 -08001282 private static void loge(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001283 Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1284 }
1285
1286 public int getActivePhoneType() {
Wink Saville36469e72014-06-11 15:17:00 -07001287 return getActivePhoneTypeUsingSubId(getDefaultSubscription());
1288 }
1289
1290 public int getActivePhoneTypeUsingSubId(long subId) {
1291 return getPhone(subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001292 }
1293
1294 /**
1295 * Returns the CDMA ERI icon index to display
1296 */
1297 public int getCdmaEriIconIndex() {
Wink Saville36469e72014-06-11 15:17:00 -07001298 return getCdmaEriIconIndexUsingSubId(getDefaultSubscription());
1299
1300 }
1301
1302 public int getCdmaEriIconIndexUsingSubId(long subId) {
1303 return getPhone(subId).getCdmaEriIconIndex();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001304 }
1305
1306 /**
1307 * Returns the CDMA ERI icon mode,
1308 * 0 - ON
1309 * 1 - FLASHING
1310 */
1311 public int getCdmaEriIconMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001312 return getCdmaEriIconModeUsingSubId(getDefaultSubscription());
1313 }
1314
1315 public int getCdmaEriIconModeUsingSubId(long subId) {
1316 return getPhone(subId).getCdmaEriIconMode();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001317 }
1318
1319 /**
1320 * Returns the CDMA ERI text,
1321 */
1322 public String getCdmaEriText() {
Wink Saville36469e72014-06-11 15:17:00 -07001323 return getCdmaEriTextUsingSubId(getDefaultSubscription());
1324 }
1325
1326 public String getCdmaEriTextUsingSubId(long subId) {
1327 return getPhone(subId).getCdmaEriText();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001328 }
1329
1330 /**
1331 * Returns true if CDMA provisioning needs to run.
1332 */
1333 public boolean needsOtaServiceProvisioning() {
1334 return mPhone.needsOtaServiceProvisioning();
1335 }
1336
1337 /**
1338 * Returns the unread count of voicemails
1339 */
1340 public int getVoiceMessageCount() {
Wink Saville36469e72014-06-11 15:17:00 -07001341 return getVoiceMessageCountUsingSubId(getDefaultSubscription());
1342 }
1343
1344 /**
1345 * Returns the unread count of voicemails for a subId
1346 */
1347 public int getVoiceMessageCountUsingSubId( long subId) {
1348 return getPhone(subId).getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001349 }
1350
1351 /**
1352 * Returns the data network type
1353 *
1354 * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1355 */
1356 @Override
1357 public int getNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001358 return getNetworkTypeUsingSubId(getDefaultSubscription());
1359 }
1360
1361 /**
1362 * Returns the network type for a subId
1363 */
1364 @Override
1365 public int getNetworkTypeUsingSubId(long subId) {
1366 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001367 }
1368
1369 /**
1370 * Returns the data network type
1371 */
1372 @Override
1373 public int getDataNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001374 return getDataNetworkTypeUsingSubId(getDefaultSubscription());
1375 }
1376
1377 /**
1378 * Returns the data network type for a subId
1379 */
1380 @Override
1381 public int getDataNetworkTypeUsingSubId(long subId) {
1382 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001383 }
1384
1385 /**
1386 * Returns the data network type
1387 */
1388 @Override
1389 public int getVoiceNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001390 return getVoiceNetworkTypeUsingSubId(getDefaultSubscription());
1391 }
1392
1393 /**
1394 * Returns the Voice network type for a subId
1395 */
1396 @Override
1397 public int getVoiceNetworkTypeUsingSubId(long subId) {
1398 return getPhone(subId).getServiceState().getVoiceNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001399 }
1400
1401 /**
1402 * @return true if a ICC card is present
1403 */
1404 public boolean hasIccCard() {
Wink Saville36469e72014-06-11 15:17:00 -07001405 // FIXME Make changes to pass defaultSimId of type int
1406 return hasIccCardUsingSlotId(getDefaultSubscription());
1407 }
1408
1409 /**
1410 * @return true if a ICC card is present for a slotId
1411 */
1412 public boolean hasIccCardUsingSlotId(long slotId) {
1413 return getPhone(slotId).getIccCard().hasIccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001414 }
1415
1416 /**
1417 * Return if the current radio is LTE on CDMA. This
1418 * is a tri-state return value as for a period of time
1419 * the mode may be unknown.
1420 *
1421 * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
Jake Hambye994d462014-02-03 13:10:13 -08001422 * or {@link Phone#LTE_ON_CDMA_TRUE}
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001423 */
1424 public int getLteOnCdmaMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001425 return getLteOnCdmaModeUsingSubId(getDefaultSubscription());
1426 }
1427
1428 public int getLteOnCdmaModeUsingSubId(long subId) {
1429 return getPhone(subId).getLteOnCdmaMode();
1430 }
1431
1432 public void setPhone(Phone phone) {
1433 mPhone = phone;
1434 }
1435
1436 /**
1437 * {@hide}
1438 * Returns Default subId, 0 in the case of single standby.
1439 */
1440 private long getDefaultSubscription() {
1441 return SubscriptionManager.getDefaultSubId();
1442 }
1443
1444 private long getPreferredVoiceSubscription() {
1445 return SubscriptionManager.getDefaultVoiceSubId();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001446 }
Ihab Awadf2177b72013-11-25 13:33:23 -08001447
1448 /**
1449 * @see android.telephony.TelephonyManager.WifiCallingChoices
1450 */
1451 public int getWhenToMakeWifiCalls() {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001452 return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1453 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
Ihab Awadf2177b72013-11-25 13:33:23 -08001454 }
1455
1456 /**
1457 * @see android.telephony.TelephonyManager.WifiCallingChoices
1458 */
1459 public void setWhenToMakeWifiCalls(int preference) {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001460 if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1461 Settings.System.putInt(mPhone.getContext().getContentResolver(),
1462 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
Ihab Awadf9e92732013-12-05 18:02:52 -08001463 }
1464
Sailesh Nepald1e68152013-12-12 19:08:02 -08001465 private static int getWhenToMakeWifiCallsDefaultPreference() {
1466 // TODO(sail): Use a build property to choose this value.
Evan Charlton9829e882013-12-19 15:30:38 -08001467 return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
Ihab Awadf2177b72013-11-25 13:33:23 -08001468 }
Shishir Agrawal69f68122013-12-16 17:25:49 -08001469
Shishir Agrawal566b7612013-10-28 14:41:00 -07001470 @Override
1471 public int iccOpenLogicalChannel(String AID) {
Junda Liua2e36012014-07-09 18:30:01 -07001472 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001473
1474 if (DBG) log("iccOpenLogicalChannel: " + AID);
1475 Integer channel = (Integer)sendRequest(CMD_OPEN_CHANNEL, AID);
1476 if (DBG) log("iccOpenLogicalChannel: " + channel);
Jake Hambye994d462014-02-03 13:10:13 -08001477 return channel;
Shishir Agrawal566b7612013-10-28 14:41:00 -07001478 }
1479
1480 @Override
1481 public boolean iccCloseLogicalChannel(int channel) {
Junda Liua2e36012014-07-09 18:30:01 -07001482 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001483
1484 if (DBG) log("iccCloseLogicalChannel: " + channel);
1485 if (channel < 0) {
1486 return false;
1487 }
Jake Hambye994d462014-02-03 13:10:13 -08001488 Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
Shishir Agrawal566b7612013-10-28 14:41:00 -07001489 if (DBG) log("iccCloseLogicalChannel: " + success);
1490 return success;
1491 }
1492
1493 @Override
1494 public String iccTransmitApduLogicalChannel(int channel, int cla,
1495 int command, int p1, int p2, int p3, String data) {
Junda Liua2e36012014-07-09 18:30:01 -07001496 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001497
1498 if (DBG) {
1499 log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1500 " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1501 " data=" + data);
1502 }
1503
1504 if (channel < 0) {
1505 return "";
1506 }
1507
1508 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU,
1509 new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1510 if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1511
1512 // If the payload is null, there was an error. Indicate that by returning
1513 // an empty string.
1514 if (response.payload == null) {
1515 return "";
1516 }
1517
1518 // Append the returned status code to the end of the response payload.
1519 String s = Integer.toHexString(
1520 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1521 s = IccUtils.bytesToHexString(response.payload) + s;
1522 return s;
1523 }
Jake Hambye994d462014-02-03 13:10:13 -08001524
Evan Charltonc66da362014-05-16 14:06:40 -07001525 @Override
1526 public String sendEnvelopeWithStatus(String content) {
Junda Liua2e36012014-07-09 18:30:01 -07001527 enforceModifyPermissionOrCarrierPrivilege();
Evan Charltonc66da362014-05-16 14:06:40 -07001528
1529 IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
1530 if (response.payload == null) {
1531 return "";
1532 }
1533
1534 // Append the returned status code to the end of the response payload.
1535 String s = Integer.toHexString(
1536 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1537 s = IccUtils.bytesToHexString(response.payload) + s;
1538 return s;
1539 }
1540
Jake Hambye994d462014-02-03 13:10:13 -08001541 /**
1542 * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1543 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1544 *
1545 * @param itemID the ID of the item to read
1546 * @return the NV item as a String, or null on error.
1547 */
1548 @Override
1549 public String nvReadItem(int itemID) {
Junda Liua2e36012014-07-09 18:30:01 -07001550 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001551 if (DBG) log("nvReadItem: item " + itemID);
1552 String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
1553 if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
1554 return value;
1555 }
1556
1557 /**
1558 * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1559 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1560 *
1561 * @param itemID the ID of the item to read
1562 * @param itemValue the value to write, as a String
1563 * @return true on success; false on any failure
1564 */
1565 @Override
1566 public boolean nvWriteItem(int itemID, String itemValue) {
Junda Liua2e36012014-07-09 18:30:01 -07001567 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001568 if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
1569 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
1570 new Pair<Integer, String>(itemID, itemValue));
1571 if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
1572 return success;
1573 }
1574
1575 /**
1576 * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
1577 * Used for device configuration by some CDMA operators.
1578 *
1579 * @param preferredRoamingList byte array containing the new PRL
1580 * @return true on success; false on any failure
1581 */
1582 @Override
1583 public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
Junda Liua2e36012014-07-09 18:30:01 -07001584 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001585 if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
1586 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
1587 if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
1588 return success;
1589 }
1590
1591 /**
1592 * Perform the specified type of NV config reset.
1593 * Used for device configuration by some CDMA operators.
1594 *
1595 * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
1596 * @return true on success; false on any failure
1597 */
1598 @Override
1599 public boolean nvResetConfig(int resetType) {
Junda Liua2e36012014-07-09 18:30:01 -07001600 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001601 if (DBG) log("nvResetConfig: type " + resetType);
1602 Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
1603 if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
1604 return success;
1605 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001606
1607 /**
Wink Saville36469e72014-06-11 15:17:00 -07001608 * {@hide}
1609 * Returns Default sim, 0 in the case of single standby.
1610 */
1611 public int getDefaultSim() {
1612 //TODO Need to get it from Telephony Devcontroller
1613 return 0;
1614 }
1615
ram87fca6f2014-07-18 18:58:44 +05301616 public String[] getPcscfAddress(String apnType) {
Wink Saville36469e72014-06-11 15:17:00 -07001617 enforceReadPermission();
ram87fca6f2014-07-18 18:58:44 +05301618 return mPhone.getPcscfAddress(apnType);
Wink Saville36469e72014-06-11 15:17:00 -07001619 }
1620
1621 public void setImsRegistrationState(boolean registered) {
1622 enforceModifyPermission();
1623 mPhone.setImsRegistrationState(registered);
1624 }
1625
1626 /**
Junda Liu84d15a22014-07-02 11:21:04 -07001627 * Get the calculated preferred network type.
1628 * Used for debugging incorrect network type.
1629 *
1630 * @return the preferred network type, defined in RILConstants.java.
1631 */
1632 @Override
1633 public int getCalculatedPreferredNetworkType() {
1634 enforceReadPermission();
1635 return PhoneFactory.calculatePreferredNetworkType(mPhone.getContext());
1636 }
1637
1638 /**
Jake Hamby7c27be32014-03-03 13:25:59 -08001639 * Get the preferred network type.
1640 * Used for device configuration by some CDMA operators.
1641 *
1642 * @return the preferred network type, defined in RILConstants.java.
1643 */
1644 @Override
1645 public int getPreferredNetworkType() {
Junda Liua2e36012014-07-09 18:30:01 -07001646 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001647 if (DBG) log("getPreferredNetworkType");
1648 int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null);
1649 int networkType = (result != null ? result[0] : -1);
1650 if (DBG) log("getPreferredNetworkType: " + networkType);
1651 return networkType;
1652 }
1653
1654 /**
1655 * Set the preferred network type.
1656 * Used for device configuration by some CDMA operators.
1657 *
1658 * @param networkType the preferred network type, defined in RILConstants.java.
1659 * @return true on success; false on any failure.
1660 */
1661 @Override
1662 public boolean setPreferredNetworkType(int networkType) {
Junda Liua2e36012014-07-09 18:30:01 -07001663 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001664 if (DBG) log("setPreferredNetworkType: type " + networkType);
1665 Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType);
1666 if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
Junda Liu80bc0d12014-07-14 16:36:44 -07001667 if (success) {
1668 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1669 Settings.Global.PREFERRED_NETWORK_MODE, networkType);
1670 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001671 return success;
1672 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001673
1674 /**
Junda Liu787bc7e2014-06-30 13:38:02 -07001675 * Set the CDMA subscription source.
1676 * Used for device supporting both NV and RUIM for CDMA.
1677 *
1678 * @param subscriptionType the subscription type, 0 for RUIM, 1 for NV.
1679 * @return true on success; false on any failure.
1680 */
1681 @Override
1682 public boolean setCdmaSubscription(int subscriptionType) {
Junda Liua2e36012014-07-09 18:30:01 -07001683 enforceModifyPermissionOrCarrierPrivilege();
Junda Liu787bc7e2014-06-30 13:38:02 -07001684 if (DBG) log("setCdmaSubscription: type " + subscriptionType);
1685 if (subscriptionType != mPhone.CDMA_SUBSCRIPTION_RUIM_SIM &&
1686 subscriptionType != mPhone.CDMA_SUBSCRIPTION_NV) {
1687 loge("setCdmaSubscription: unsupported subscriptionType.");
1688 return false;
1689 }
1690 Boolean success = (Boolean) sendRequest(CMD_SET_CDMA_SUBSCRIPTION, subscriptionType);
1691 if (DBG) log("setCdmaSubscription: " + (success ? "ok" : "fail"));
1692 if (success) {
1693 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1694 Settings.Global.CDMA_SUBSCRIPTION_MODE, subscriptionType);
1695 }
1696 return success;
1697 }
1698
1699 /**
Robert Greenwalted86e582014-05-21 20:03:20 -07001700 * Set mobile data enabled
1701 * Used by the user through settings etc to turn on/off mobile data
1702 *
1703 * @param enable {@code true} turn turn data on, else {@code false}
1704 */
1705 @Override
1706 public void setDataEnabled(boolean enable) {
1707 enforceModifyPermission();
1708 mPhone.setDataEnabled(enable);
1709 }
1710
1711 /**
Robert Greenwalt646120a2014-05-23 11:54:03 -07001712 * Get whether mobile data is enabled.
1713 *
1714 * Note that this used to be available from ConnectivityService, gated by
1715 * ACCESS_NETWORK_STATE permission, so this will accept either that or
1716 * our MODIFY_PHONE_STATE.
Robert Greenwalted86e582014-05-21 20:03:20 -07001717 *
1718 * @return {@code true} if data is enabled else {@code false}
1719 */
1720 @Override
1721 public boolean getDataEnabled() {
Robert Greenwalt646120a2014-05-23 11:54:03 -07001722 try {
1723 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
1724 null);
1725 } catch (Exception e) {
1726 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
1727 null);
1728 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001729 return mPhone.getDataEnabled();
1730 }
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001731
1732 @Override
1733 public int hasCarrierPrivileges() {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001734 UiccCard card = UiccController.getInstance().getUiccCard();
1735 if (card == null) {
1736 loge("hasCarrierPrivileges: No UICC");
1737 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1738 }
1739 return card.getCarrierPrivilegeStatusForCurrentTransaction(
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001740 mPhone.getContext().getPackageManager());
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001741 }
Junda Liu29340342014-07-10 15:23:27 -07001742
1743 @Override
Shishir Agrawal6d5a2852014-07-11 16:32:57 -07001744 public int checkCarrierPrivilegesForPackage(String pkgname) {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001745 UiccCard card = UiccController.getInstance().getUiccCard();
1746 if (card == null) {
1747 loge("checkCarrierPrivilegesForPackage: No UICC");
1748 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1749 }
1750 return card.getCarrierPrivilegeStatus(mPhone.getContext().getPackageManager(), pkgname);
Junda Liu29340342014-07-10 15:23:27 -07001751 }
Derek Tan89e89d42014-07-08 17:00:10 -07001752
1753 @Override
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001754 public List<String> getCarrierPackageNamesForBroadcastIntent(Intent intent) {
1755 UiccCard card = UiccController.getInstance().getUiccCard();
1756 if (card == null) {
1757 loge("getCarrierPackageNamesForBroadcastIntent: No UICC");
1758 return null ;
1759 }
1760 return card.getCarrierPackageNamesForBroadcastIntent(
1761 mPhone.getContext().getPackageManager(), intent);
1762 }
1763
1764 @Override
Derek Tan89e89d42014-07-08 17:00:10 -07001765 public void enableSimplifiedNetworkSettings(long subId, boolean enable) {
Derek Tan352d8cd2014-07-12 12:57:11 -07001766 enforceModifyPermissionOrCarrierPrivilege();
Derek Tan89e89d42014-07-08 17:00:10 -07001767 if (enable) {
1768 mSimplifiedNetworkSettings.add(subId);
1769 } else {
1770 mSimplifiedNetworkSettings.remove(subId);
1771 }
1772 }
1773
1774 @Override
1775 public boolean getSimplifiedNetworkSettingsEnabled(long subId) {
1776 enforceReadPermission();
1777 return mSimplifiedNetworkSettings.contains(subId);
1778 }
Derek Tan7226c842014-07-02 17:42:23 -07001779
1780 @Override
1781 public void setLine1NumberForDisplay(long subId, String alphaTag, String number) {
Derek Tan352d8cd2014-07-12 12:57:11 -07001782 enforceModifyPermissionOrCarrierPrivilege();
Derek Tan7226c842014-07-02 17:42:23 -07001783 mAdnRecordsForDisplay.put(subId, new AdnRecord(alphaTag, number));
1784 }
1785
1786 @Override
1787 public String getLine1NumberForDisplay(long subId) {
1788 enforceReadPermission();
1789 if (!mAdnRecordsForDisplay.containsKey(subId)) {
1790 return null;
1791 }
1792 AdnRecord adnRecord = mAdnRecordsForDisplay.get(subId);
1793 if (adnRecord.getNumber() == null || adnRecord.getNumber().isEmpty()) {
1794 return null;
1795 }
1796 return adnRecord.getNumber();
1797 }
1798
1799 @Override
1800 public String getLine1AlphaTagForDisplay(long subId) {
1801 enforceReadPermission();
1802 if (!mAdnRecordsForDisplay.containsKey(subId)) {
1803 return null;
1804 }
1805 AdnRecord adnRecord = mAdnRecordsForDisplay.get(subId);
1806 if (adnRecord.getAlphaTag() == null || adnRecord.getAlphaTag().isEmpty()) {
1807 return null;
1808 }
1809 return adnRecord.getAlphaTag();
1810 }
Shishir Agrawalb1ebf8c2014-07-17 16:32:41 -07001811
1812 @Override
1813 public boolean setOperatorBrandOverride(String iccId, String brand) {
1814 enforceModifyPermissionOrCarrierPrivilege();
1815 return mPhone.setOperatorBrandOverride(iccId, brand);
1816 }
Steven Liu4bf01bc2014-07-17 11:05:29 -05001817
1818 @Override
1819 public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
1820 enforceModifyPermission();
1821
1822 int returnValue = 0;
1823 try {
1824 AsyncResult result = (AsyncResult)sendRequest(CMD_INVOKE_OEM_RIL_REQUEST_RAW, oemReq);
1825 if(result.exception == null) {
1826 if (result.result != null) {
1827 byte[] responseData = (byte[])(result.result);
1828 if(responseData.length > oemResp.length) {
1829 Log.w(LOG_TAG, "Buffer to copy response too small: Response length is " +
1830 responseData.length + "bytes. Buffer Size is " +
1831 oemResp.length + "bytes.");
1832 }
1833 System.arraycopy(responseData, 0, oemResp, 0, responseData.length);
1834 returnValue = responseData.length;
1835 }
1836 } else {
1837 CommandException ex = (CommandException) result.exception;
1838 returnValue = ex.getCommandError().ordinal();
1839 if(returnValue > 0) returnValue *= -1;
1840 }
1841 } catch (RuntimeException e) {
1842 Log.w(LOG_TAG, "sendOemRilRequestRaw: Runtime Exception");
1843 returnValue = (CommandException.Error.GENERIC_FAILURE.ordinal());
1844 if(returnValue > 0) returnValue *= -1;
1845 }
1846
1847 return returnValue;
1848 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001849}