blob: dad9cee716529d7ce5d3d7302edbce659f884a8a [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;
Shishir Agrawal566b7612013-10-28 14:41:00 -070062import com.android.internal.telephony.uicc.IccIoResult;
63import com.android.internal.telephony.uicc.IccUtils;
Shishir Agrawal60f9c952014-06-23 12:00:43 -070064import com.android.internal.telephony.uicc.UiccCarrierPrivilegeRules;
Shishir Agrawal566b7612013-10-28 14:41:00 -070065import com.android.internal.telephony.uicc.UiccController;
Jake Hambye994d462014-02-03 13:10:13 -080066import com.android.internal.util.HexDump;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070067
Wink Saville36469e72014-06-11 15:17:00 -070068import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
69
Santos Cordon7d4ddf62013-07-10 11:58:08 -070070import java.util.ArrayList;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070071import java.util.HashMap;
Derek Tan89e89d42014-07-08 17:00:10 -070072import java.util.HashSet;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070073import java.util.Iterator;
Jake Hambye994d462014-02-03 13:10:13 -080074import java.util.List;
Gabriel Peal36ebb0d2014-03-20 09:20:43 -070075import java.util.Map;
Derek Tan89e89d42014-07-08 17:00:10 -070076import java.util.Set;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070077
78/**
79 * Implementation of the ITelephony interface.
80 */
Santos Cordon117fee72014-05-16 17:56:12 -070081public class PhoneInterfaceManager extends ITelephony.Stub {
Santos Cordon7d4ddf62013-07-10 11:58:08 -070082 private static final String LOG_TAG = "PhoneInterfaceManager";
83 private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
84 private static final boolean DBG_LOC = false;
85
86 // Message codes used with mMainThreadHandler
87 private static final int CMD_HANDLE_PIN_MMI = 1;
88 private static final int CMD_HANDLE_NEIGHBORING_CELL = 2;
89 private static final int EVENT_NEIGHBORING_CELL_DONE = 3;
90 private static final int CMD_ANSWER_RINGING_CALL = 4;
91 private static final int CMD_END_CALL = 5; // not used yet
92 private static final int CMD_SILENCE_RINGER = 6;
Shishir Agrawal566b7612013-10-28 14:41:00 -070093 private static final int CMD_TRANSMIT_APDU = 7;
94 private static final int EVENT_TRANSMIT_APDU_DONE = 8;
95 private static final int CMD_OPEN_CHANNEL = 9;
96 private static final int EVENT_OPEN_CHANNEL_DONE = 10;
97 private static final int CMD_CLOSE_CHANNEL = 11;
98 private static final int EVENT_CLOSE_CHANNEL_DONE = 12;
Jake Hambye994d462014-02-03 13:10:13 -080099 private static final int CMD_NV_READ_ITEM = 13;
100 private static final int EVENT_NV_READ_ITEM_DONE = 14;
101 private static final int CMD_NV_WRITE_ITEM = 15;
102 private static final int EVENT_NV_WRITE_ITEM_DONE = 16;
103 private static final int CMD_NV_WRITE_CDMA_PRL = 17;
104 private static final int EVENT_NV_WRITE_CDMA_PRL_DONE = 18;
105 private static final int CMD_NV_RESET_CONFIG = 19;
106 private static final int EVENT_NV_RESET_CONFIG_DONE = 20;
Jake Hamby7c27be32014-03-03 13:25:59 -0800107 private static final int CMD_GET_PREFERRED_NETWORK_TYPE = 21;
108 private static final int EVENT_GET_PREFERRED_NETWORK_TYPE_DONE = 22;
109 private static final int CMD_SET_PREFERRED_NETWORK_TYPE = 23;
110 private static final int EVENT_SET_PREFERRED_NETWORK_TYPE_DONE = 24;
Sailesh Nepal35b59452014-03-06 09:26:56 -0800111 private static final int CMD_SEND_ENVELOPE = 25;
112 private static final int EVENT_SEND_ENVELOPE_DONE = 26;
Junda Liu787bc7e2014-06-30 13:38:02 -0700113 private static final int CMD_SET_CDMA_SUBSCRIPTION = 27;
114 private static final int EVENT_SET_CDMA_SUBSCRIPTION_DONE = 28;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700115
116 /** The singleton instance. */
117 private static PhoneInterfaceManager sInstance;
118
119 PhoneGlobals mApp;
120 Phone mPhone;
121 CallManager mCM;
122 AppOpsManager mAppOps;
123 MainThreadHandler mMainThreadHandler;
124
125 /**
Derek Tan89e89d42014-07-08 17:00:10 -0700126 * Indicates if Android should display a simplified Mobile Network Settings UI in a specific
127 * subscription.
128 */
129 Set<Long> mSimplifiedNetworkSettings;
130
131 /**
Shishir Agrawal566b7612013-10-28 14:41:00 -0700132 * A request object to use for transmitting data to an ICC.
133 */
134 private static final class IccAPDUArgument {
135 public int channel, cla, command, p1, p2, p3;
136 public String data;
137
138 public IccAPDUArgument(int channel, int cla, int command,
139 int p1, int p2, int p3, String data) {
140 this.channel = channel;
141 this.cla = cla;
142 this.command = command;
143 this.p1 = p1;
144 this.p2 = p2;
145 this.p3 = p3;
146 this.data = data;
147 }
148 }
149
150 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700151 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
152 * request after sending. The main thread will notify the request when it is complete.
153 */
154 private static final class MainThreadRequest {
155 /** The argument to use for the request */
156 public Object argument;
157 /** The result of the request that is run on the main thread */
158 public Object result;
159
160 public MainThreadRequest(Object argument) {
161 this.argument = argument;
162 }
163 }
164
Sailesh Nepalcc0375f2013-11-13 09:15:18 -0800165 private static final class IncomingThirdPartyCallArgs {
166 public final ComponentName component;
167 public final String callId;
168 public final String callerDisplayName;
169
170 public IncomingThirdPartyCallArgs(ComponentName component, String callId,
171 String callerDisplayName) {
172 this.component = component;
173 this.callId = callId;
174 this.callerDisplayName = callerDisplayName;
175 }
176 }
177
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700178 /**
179 * A handler that processes messages on the main thread in the phone process. Since many
180 * of the Phone calls are not thread safe this is needed to shuttle the requests from the
181 * inbound binder threads to the main thread in the phone process. The Binder thread
182 * may provide a {@link MainThreadRequest} object in the msg.obj field that they are waiting
183 * on, which will be notified when the operation completes and will contain the result of the
184 * request.
185 *
186 * <p>If a MainThreadRequest object is provided in the msg.obj field,
187 * note that request.result must be set to something non-null for the calling thread to
188 * unblock.
189 */
190 private final class MainThreadHandler extends Handler {
191 @Override
192 public void handleMessage(Message msg) {
193 MainThreadRequest request;
194 Message onCompleted;
195 AsyncResult ar;
196
197 switch (msg.what) {
198 case CMD_HANDLE_PIN_MMI:
199 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800200 request.result = mPhone.handlePinMmi((String) request.argument);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700201 // Wake up the requesting thread
202 synchronized (request) {
203 request.notifyAll();
204 }
205 break;
206
207 case CMD_HANDLE_NEIGHBORING_CELL:
208 request = (MainThreadRequest) msg.obj;
209 onCompleted = obtainMessage(EVENT_NEIGHBORING_CELL_DONE,
210 request);
211 mPhone.getNeighboringCids(onCompleted);
212 break;
213
214 case EVENT_NEIGHBORING_CELL_DONE:
215 ar = (AsyncResult) msg.obj;
216 request = (MainThreadRequest) ar.userObj;
217 if (ar.exception == null && ar.result != null) {
218 request.result = ar.result;
219 } else {
220 // create an empty list to notify the waiting thread
Jake Hambye994d462014-02-03 13:10:13 -0800221 request.result = new ArrayList<NeighboringCellInfo>(0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700222 }
223 // Wake up the requesting thread
224 synchronized (request) {
225 request.notifyAll();
226 }
227 break;
228
229 case CMD_ANSWER_RINGING_CALL:
230 answerRingingCallInternal();
231 break;
232
233 case CMD_SILENCE_RINGER:
234 silenceRingerInternal();
235 break;
236
237 case CMD_END_CALL:
238 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800239 boolean hungUp;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700240 int phoneType = mPhone.getPhoneType();
241 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
242 // CDMA: If the user presses the Power button we treat it as
243 // ending the complete call session
244 hungUp = PhoneUtils.hangupRingingAndActive(mPhone);
245 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
246 // GSM: End the call as per the Phone state
247 hungUp = PhoneUtils.hangup(mCM);
248 } else {
249 throw new IllegalStateException("Unexpected phone type: " + phoneType);
250 }
251 if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up"));
252 request.result = hungUp;
253 // Wake up the requesting thread
254 synchronized (request) {
255 request.notifyAll();
256 }
257 break;
258
Shishir Agrawal566b7612013-10-28 14:41:00 -0700259 case CMD_TRANSMIT_APDU:
260 request = (MainThreadRequest) msg.obj;
261 IccAPDUArgument argument = (IccAPDUArgument) request.argument;
262 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_DONE, request);
263 UiccController.getInstance().getUiccCard().iccTransmitApduLogicalChannel(
264 argument.channel, argument.cla, argument.command,
265 argument.p1, argument.p2, argument.p3, argument.data,
266 onCompleted);
267 break;
268
269 case EVENT_TRANSMIT_APDU_DONE:
270 ar = (AsyncResult) msg.obj;
271 request = (MainThreadRequest) ar.userObj;
272 if (ar.exception == null && ar.result != null) {
273 request.result = ar.result;
274 } else {
275 request.result = new IccIoResult(0x6F, 0, (byte[])null);
276 if (ar.result == null) {
277 loge("iccTransmitApduLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800278 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700279 loge("iccTransmitApduLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800280 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700281 } else {
282 loge("iccTransmitApduLogicalChannel: Unknown exception");
283 }
284 }
285 synchronized (request) {
286 request.notifyAll();
287 }
288 break;
289
Derek Tan4d5e5c12014-02-04 11:54:58 -0800290 case CMD_SEND_ENVELOPE:
291 request = (MainThreadRequest) msg.obj;
292 onCompleted = obtainMessage(EVENT_SEND_ENVELOPE_DONE, request);
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700293 UiccController.getInstance().getUiccCard().sendEnvelopeWithStatus(
Derek Tan4d5e5c12014-02-04 11:54:58 -0800294 (String)request.argument, onCompleted);
295 break;
296
297 case EVENT_SEND_ENVELOPE_DONE:
298 ar = (AsyncResult) msg.obj;
299 request = (MainThreadRequest) ar.userObj;
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700300 if (ar.exception == null && ar.result != null) {
301 request.result = ar.result;
Derek Tan4d5e5c12014-02-04 11:54:58 -0800302 } else {
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700303 request.result = new IccIoResult(0x6F, 0, (byte[])null);
304 if (ar.result == null) {
305 loge("sendEnvelopeWithStatus: Empty response");
306 } else if (ar.exception instanceof CommandException) {
307 loge("sendEnvelopeWithStatus: CommandException: " +
308 ar.exception);
309 } else {
310 loge("sendEnvelopeWithStatus: exception:" + ar.exception);
311 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800312 }
313 synchronized (request) {
314 request.notifyAll();
315 }
316 break;
317
Shishir Agrawal566b7612013-10-28 14:41:00 -0700318 case CMD_OPEN_CHANNEL:
319 request = (MainThreadRequest) msg.obj;
320 onCompleted = obtainMessage(EVENT_OPEN_CHANNEL_DONE, request);
321 UiccController.getInstance().getUiccCard().iccOpenLogicalChannel(
322 (String)request.argument, onCompleted);
323 break;
324
325 case EVENT_OPEN_CHANNEL_DONE:
326 ar = (AsyncResult) msg.obj;
327 request = (MainThreadRequest) ar.userObj;
328 if (ar.exception == null && ar.result != null) {
Jake Hambye994d462014-02-03 13:10:13 -0800329 request.result = ((int[]) ar.result)[0];
Shishir Agrawal566b7612013-10-28 14:41:00 -0700330 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800331 request.result = -1;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700332 if (ar.result == null) {
333 loge("iccOpenLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800334 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700335 loge("iccOpenLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800336 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700337 } else {
338 loge("iccOpenLogicalChannel: Unknown exception");
339 }
340 }
341 synchronized (request) {
342 request.notifyAll();
343 }
344 break;
345
346 case CMD_CLOSE_CHANNEL:
347 request = (MainThreadRequest) msg.obj;
348 onCompleted = obtainMessage(EVENT_CLOSE_CHANNEL_DONE,
349 request);
350 UiccController.getInstance().getUiccCard().iccCloseLogicalChannel(
Jake Hambye994d462014-02-03 13:10:13 -0800351 (Integer) request.argument,
Shishir Agrawal566b7612013-10-28 14:41:00 -0700352 onCompleted);
353 break;
354
355 case EVENT_CLOSE_CHANNEL_DONE:
Jake Hambye994d462014-02-03 13:10:13 -0800356 handleNullReturnEvent(msg, "iccCloseLogicalChannel");
357 break;
358
359 case CMD_NV_READ_ITEM:
360 request = (MainThreadRequest) msg.obj;
361 onCompleted = obtainMessage(EVENT_NV_READ_ITEM_DONE, request);
362 mPhone.nvReadItem((Integer) request.argument, onCompleted);
363 break;
364
365 case EVENT_NV_READ_ITEM_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700366 ar = (AsyncResult) msg.obj;
367 request = (MainThreadRequest) ar.userObj;
Jake Hambye994d462014-02-03 13:10:13 -0800368 if (ar.exception == null && ar.result != null) {
369 request.result = ar.result; // String
Shishir Agrawal566b7612013-10-28 14:41:00 -0700370 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800371 request.result = "";
372 if (ar.result == null) {
373 loge("nvReadItem: Empty response");
374 } else if (ar.exception instanceof CommandException) {
375 loge("nvReadItem: CommandException: " +
376 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700377 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800378 loge("nvReadItem: Unknown exception");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700379 }
380 }
381 synchronized (request) {
382 request.notifyAll();
383 }
384 break;
385
Jake Hambye994d462014-02-03 13:10:13 -0800386 case CMD_NV_WRITE_ITEM:
387 request = (MainThreadRequest) msg.obj;
388 onCompleted = obtainMessage(EVENT_NV_WRITE_ITEM_DONE, request);
389 Pair<Integer, String> idValue = (Pair<Integer, String>) request.argument;
390 mPhone.nvWriteItem(idValue.first, idValue.second, onCompleted);
391 break;
392
393 case EVENT_NV_WRITE_ITEM_DONE:
394 handleNullReturnEvent(msg, "nvWriteItem");
395 break;
396
397 case CMD_NV_WRITE_CDMA_PRL:
398 request = (MainThreadRequest) msg.obj;
399 onCompleted = obtainMessage(EVENT_NV_WRITE_CDMA_PRL_DONE, request);
400 mPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
401 break;
402
403 case EVENT_NV_WRITE_CDMA_PRL_DONE:
404 handleNullReturnEvent(msg, "nvWriteCdmaPrl");
405 break;
406
407 case CMD_NV_RESET_CONFIG:
408 request = (MainThreadRequest) msg.obj;
409 onCompleted = obtainMessage(EVENT_NV_RESET_CONFIG_DONE, request);
410 mPhone.nvResetConfig((Integer) request.argument, onCompleted);
411 break;
412
413 case EVENT_NV_RESET_CONFIG_DONE:
414 handleNullReturnEvent(msg, "nvResetConfig");
415 break;
416
Jake Hamby7c27be32014-03-03 13:25:59 -0800417 case CMD_GET_PREFERRED_NETWORK_TYPE:
418 request = (MainThreadRequest) msg.obj;
419 onCompleted = obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE_DONE, request);
420 mPhone.getPreferredNetworkType(onCompleted);
421 break;
422
423 case EVENT_GET_PREFERRED_NETWORK_TYPE_DONE:
424 ar = (AsyncResult) msg.obj;
425 request = (MainThreadRequest) ar.userObj;
426 if (ar.exception == null && ar.result != null) {
427 request.result = ar.result; // Integer
428 } else {
429 request.result = -1;
430 if (ar.result == null) {
431 loge("getPreferredNetworkType: Empty response");
432 } else if (ar.exception instanceof CommandException) {
433 loge("getPreferredNetworkType: CommandException: " +
434 ar.exception);
435 } else {
436 loge("getPreferredNetworkType: Unknown exception");
437 }
438 }
439 synchronized (request) {
440 request.notifyAll();
441 }
442 break;
443
444 case CMD_SET_PREFERRED_NETWORK_TYPE:
445 request = (MainThreadRequest) msg.obj;
446 onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);
447 int networkType = (Integer) request.argument;
448 mPhone.setPreferredNetworkType(networkType, onCompleted);
449 break;
450
451 case EVENT_SET_PREFERRED_NETWORK_TYPE_DONE:
452 handleNullReturnEvent(msg, "setPreferredNetworkType");
453 break;
454
Junda Liu787bc7e2014-06-30 13:38:02 -0700455 case CMD_SET_CDMA_SUBSCRIPTION:
456 request = (MainThreadRequest) msg.obj;
457 onCompleted = obtainMessage(EVENT_SET_CDMA_SUBSCRIPTION_DONE, request);
458 int subscriptionType = (Integer) request.argument;
459 mPhone.setCdmaSubscription(subscriptionType, onCompleted);
460 break;
461
462 case EVENT_SET_CDMA_SUBSCRIPTION_DONE:
463 handleNullReturnEvent(msg, "setCdmaSubscription");
464 break;
465
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700466 default:
467 Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
468 break;
469 }
470 }
Jake Hambye994d462014-02-03 13:10:13 -0800471
472 private void handleNullReturnEvent(Message msg, String command) {
473 AsyncResult ar = (AsyncResult) msg.obj;
474 MainThreadRequest request = (MainThreadRequest) ar.userObj;
475 if (ar.exception == null) {
476 request.result = true;
477 } else {
478 request.result = false;
479 if (ar.exception instanceof CommandException) {
480 loge(command + ": CommandException: " + ar.exception);
481 } else {
482 loge(command + ": Unknown exception");
483 }
484 }
485 synchronized (request) {
486 request.notifyAll();
487 }
488 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700489 }
490
491 /**
492 * Posts the specified command to be executed on the main thread,
493 * waits for the request to complete, and returns the result.
494 * @see #sendRequestAsync
495 */
496 private Object sendRequest(int command, Object argument) {
Santos Cordon500b0e02014-06-17 10:33:33 -0700497 return sendRequest(command, argument, null);
Wink Saville36469e72014-06-11 15:17:00 -0700498 }
499
500 /**
501 * Posts the specified command to be executed on the main thread,
502 * waits for the request to complete, and returns the result.
503 * @see #sendRequestAsync
504 */
505 private Object sendRequest(int command, Object argument, Object argument2) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700506 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
507 throw new RuntimeException("This method will deadlock if called from the main thread.");
508 }
509
510 MainThreadRequest request = new MainThreadRequest(argument);
511 Message msg = mMainThreadHandler.obtainMessage(command, request);
512 msg.sendToTarget();
513
514 // Wait for the request to complete
515 synchronized (request) {
516 while (request.result == null) {
517 try {
518 request.wait();
519 } catch (InterruptedException e) {
520 // Do nothing, go back and wait until the request is complete
521 }
522 }
523 }
524 return request.result;
525 }
526
527 /**
528 * Asynchronous ("fire and forget") version of sendRequest():
529 * Posts the specified command to be executed on the main thread, and
530 * returns immediately.
531 * @see #sendRequest
532 */
533 private void sendRequestAsync(int command) {
534 mMainThreadHandler.sendEmptyMessage(command);
535 }
536
537 /**
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -0700538 * Same as {@link #sendRequestAsync(int)} except it takes an argument.
539 * @see {@link #sendRequest(int,Object)}
540 */
541 private void sendRequestAsync(int command, Object argument) {
542 MainThreadRequest request = new MainThreadRequest(argument);
543 Message msg = mMainThreadHandler.obtainMessage(command, request);
544 msg.sendToTarget();
545 }
546
547 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700548 * Initialize the singleton PhoneInterfaceManager instance.
549 * This is only done once, at startup, from PhoneApp.onCreate().
550 */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700551 /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700552 synchronized (PhoneInterfaceManager.class) {
553 if (sInstance == null) {
Sailesh Nepal194161e2014-07-03 08:57:44 -0700554 sInstance = new PhoneInterfaceManager(app, phone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700555 } else {
556 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
557 }
558 return sInstance;
559 }
560 }
561
562 /** Private constructor; @see init() */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700563 private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700564 mApp = app;
565 mPhone = phone;
566 mCM = PhoneGlobals.getInstance().mCM;
Derek Tan89e89d42014-07-08 17:00:10 -0700567 mSimplifiedNetworkSettings = new HashSet<Long>();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700568 mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
569 mMainThreadHandler = new MainThreadHandler();
570 publish();
571 }
572
573 private void publish() {
574 if (DBG) log("publish: " + this);
575
576 ServiceManager.addService("phone", this);
577 }
578
Wink Saville36469e72014-06-11 15:17:00 -0700579 // returns phone associated with the subId.
580 // getPhone(0) returns default phone in single SIM mode.
581 private Phone getPhone(long subId) {
582 // FIXME: hack for the moment
583 return mPhone;
584 // return PhoneUtils.getPhoneUsingSubId(subId);
585 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700586 //
587 // Implementation of the ITelephony interface.
588 //
589
590 public void dial(String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700591 dialUsingSubId(getPreferredVoiceSubscription(), number);
592 }
593
594 public void dialUsingSubId(long subId, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700595 if (DBG) log("dial: " + number);
596 // No permission check needed here: This is just a wrapper around the
597 // ACTION_DIAL intent, which is available to any app since it puts up
598 // the UI before it does anything.
599
600 String url = createTelUrl(number);
601 if (url == null) {
602 return;
603 }
604
605 // PENDING: should we just silently fail if phone is offhook or ringing?
Wink Saville36469e72014-06-11 15:17:00 -0700606 PhoneConstants.State state = mCM.getState(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700607 if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
608 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
609 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Wink Saville36469e72014-06-11 15:17:00 -0700610 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700611 mApp.startActivity(intent);
612 }
613 }
614
615 public void call(String callingPackage, String number) {
Wink Saville36469e72014-06-11 15:17:00 -0700616 callUsingSubId(getPreferredVoiceSubscription(), callingPackage, number);
617 }
618
619 public void callUsingSubId(long subId, String callingPackage, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700620 if (DBG) log("call: " + number);
621
622 // This is just a wrapper around the ACTION_CALL intent, but we still
623 // need to do a permission check since we're calling startActivity()
624 // from the context of the phone app.
625 enforceCallPermission();
626
627 if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
628 != AppOpsManager.MODE_ALLOWED) {
629 return;
630 }
631
632 String url = createTelUrl(number);
633 if (url == null) {
634 return;
635 }
636
637 Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
Wink Saville36469e72014-06-11 15:17:00 -0700638 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700639 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
640 mApp.startActivity(intent);
641 }
642
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700643 /**
644 * End a call based on call state
645 * @return true is a call was ended
646 */
647 public boolean endCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700648 return endCallUsingSubId(getDefaultSubscription());
649 }
650
651 /**
652 * End a call based on the call state of the subId
653 * @return true is a call was ended
654 */
655 public boolean endCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700656 enforceCallPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700657 return (Boolean) sendRequest(CMD_END_CALL, subId, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700658 }
659
660 public void answerRingingCall() {
Wink Saville36469e72014-06-11 15:17:00 -0700661 answerRingingCallUsingSubId(getDefaultSubscription());
662 }
663
664 public void answerRingingCallUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700665 if (DBG) log("answerRingingCall...");
666 // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
667 // but that can probably wait till the big TelephonyManager API overhaul.
668 // For now, protect this call with the MODIFY_PHONE_STATE permission.
669 enforceModifyPermission();
670 sendRequestAsync(CMD_ANSWER_RINGING_CALL);
671 }
672
673 /**
674 * Make the actual telephony calls to implement answerRingingCall().
675 * This should only be called from the main thread of the Phone app.
676 * @see #answerRingingCall
677 *
678 * TODO: it would be nice to return true if we answered the call, or
679 * false if there wasn't actually a ringing incoming call, or some
680 * other error occurred. (In other words, pass back the return value
681 * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
682 * But that would require calling this method via sendRequest() rather
683 * than sendRequestAsync(), and right now we don't actually *need* that
684 * return value, so let's just return void for now.
685 */
686 private void answerRingingCallInternal() {
687 final boolean hasRingingCall = !mPhone.getRingingCall().isIdle();
688 if (hasRingingCall) {
689 final boolean hasActiveCall = !mPhone.getForegroundCall().isIdle();
690 final boolean hasHoldingCall = !mPhone.getBackgroundCall().isIdle();
691 if (hasActiveCall && hasHoldingCall) {
692 // Both lines are in use!
693 // TODO: provide a flag to let the caller specify what
694 // policy to use if both lines are in use. (The current
695 // behavior is hardwired to "answer incoming, end ongoing",
696 // which is how the CALL button is specced to behave.)
697 PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
698 return;
699 } else {
700 // answerCall() will automatically hold the current active
701 // call, if there is one.
702 PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
703 return;
704 }
705 } else {
706 // No call was ringing.
707 return;
708 }
709 }
710
711 public void silenceRinger() {
712 if (DBG) log("silenceRinger...");
713 // TODO: find a more appropriate permission to check here.
714 // (That can probably wait till the big TelephonyManager API overhaul.
715 // For now, protect this call with the MODIFY_PHONE_STATE permission.)
716 enforceModifyPermission();
717 sendRequestAsync(CMD_SILENCE_RINGER);
718 }
719
720 /**
721 * Internal implemenation of silenceRinger().
722 * This should only be called from the main thread of the Phone app.
723 * @see #silenceRinger
724 */
725 private void silenceRingerInternal() {
726 if ((mCM.getState() == PhoneConstants.State.RINGING)
727 && mApp.notifier.isRinging()) {
728 // Ringer is actually playing, so silence it.
729 if (DBG) log("silenceRingerInternal: silencing...");
730 mApp.notifier.silenceRinger();
731 }
732 }
733
734 public boolean isOffhook() {
Wink Saville36469e72014-06-11 15:17:00 -0700735 return isOffhookUsingSubId(getDefaultSubscription());
736 }
737
738 public boolean isOffhookUsingSubId(long subId) {
739 return (getPhone(subId).getState() == PhoneConstants.State.OFFHOOK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700740 }
741
742 public boolean isRinging() {
Wink Saville36469e72014-06-11 15:17:00 -0700743 return (isRingingUsingSubId(getDefaultSubscription()));
744 }
745
746 public boolean isRingingUsingSubId(long subId) {
747 return (getPhone(subId).getState() == PhoneConstants.State.RINGING);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700748 }
749
750 public boolean isIdle() {
Wink Saville36469e72014-06-11 15:17:00 -0700751 return isIdleUsingSubId(getDefaultSubscription());
752 }
753
754 public boolean isIdleUsingSubId(long subId) {
755 return (getPhone(subId).getState() == PhoneConstants.State.IDLE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700756 }
757
758 public boolean isSimPinEnabled() {
759 enforceReadPermission();
760 return (PhoneGlobals.getInstance().isSimPinEnabled());
761 }
762
763 public boolean supplyPin(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700764 return supplyPinUsingSubId(getDefaultSubscription(), pin);
765 }
766
767 public boolean supplyPinUsingSubId(long subId, String pin) {
768 int [] resultArray = supplyPinReportResultUsingSubId(subId, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700769 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
770 }
771
772 public boolean supplyPuk(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700773 return supplyPukUsingSubId(getDefaultSubscription(), puk, pin);
774 }
775
776 public boolean supplyPukUsingSubId(long subId, String puk, String pin) {
777 int [] resultArray = supplyPukReportResultUsingSubId(subId, puk, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700778 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
779 }
780
781 /** {@hide} */
782 public int[] supplyPinReportResult(String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700783 return supplyPinReportResultUsingSubId(getDefaultSubscription(), pin);
784 }
785
786 public int[] supplyPinReportResultUsingSubId(long subId, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700787 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700788 final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700789 checkSimPin.start();
790 return checkSimPin.unlockSim(null, pin);
791 }
792
Wink Saville9de0f752013-10-22 19:04:03 -0700793 /** {@hide} */
794 public int[] supplyPukReportResult(String puk, String pin) {
Wink Saville36469e72014-06-11 15:17:00 -0700795 return supplyPukReportResultUsingSubId(getDefaultSubscription(), puk, pin);
796 }
797
798 public int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700799 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700800 final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700801 checkSimPuk.start();
802 return checkSimPuk.unlockSim(puk, pin);
803 }
804
805 /**
Wink Saville9de0f752013-10-22 19:04:03 -0700806 * Helper thread to turn async call to SimCard#supplyPin into
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700807 * a synchronous one.
808 */
809 private static class UnlockSim extends Thread {
810
811 private final IccCard mSimCard;
812
813 private boolean mDone = false;
Wink Saville9de0f752013-10-22 19:04:03 -0700814 private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
815 private int mRetryCount = -1;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700816
817 // For replies from SimCard interface
818 private Handler mHandler;
819
820 // For async handler to identify request type
821 private static final int SUPPLY_PIN_COMPLETE = 100;
822
823 public UnlockSim(IccCard simCard) {
824 mSimCard = simCard;
825 }
826
827 @Override
828 public void run() {
829 Looper.prepare();
830 synchronized (UnlockSim.this) {
831 mHandler = new Handler() {
832 @Override
833 public void handleMessage(Message msg) {
834 AsyncResult ar = (AsyncResult) msg.obj;
835 switch (msg.what) {
836 case SUPPLY_PIN_COMPLETE:
837 Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
838 synchronized (UnlockSim.this) {
Wink Saville9de0f752013-10-22 19:04:03 -0700839 mRetryCount = msg.arg1;
840 if (ar.exception != null) {
841 if (ar.exception instanceof CommandException &&
842 ((CommandException)(ar.exception)).getCommandError()
843 == CommandException.Error.PASSWORD_INCORRECT) {
844 mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
845 } else {
846 mResult = PhoneConstants.PIN_GENERAL_FAILURE;
847 }
848 } else {
849 mResult = PhoneConstants.PIN_RESULT_SUCCESS;
850 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700851 mDone = true;
852 UnlockSim.this.notifyAll();
853 }
854 break;
855 }
856 }
857 };
858 UnlockSim.this.notifyAll();
859 }
860 Looper.loop();
861 }
862
863 /*
864 * Use PIN or PUK to unlock SIM card
865 *
866 * If PUK is null, unlock SIM card with PIN
867 *
868 * If PUK is not null, unlock SIM card with PUK and set PIN code
869 */
Wink Saville9de0f752013-10-22 19:04:03 -0700870 synchronized int[] unlockSim(String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700871
872 while (mHandler == null) {
873 try {
874 wait();
875 } catch (InterruptedException e) {
876 Thread.currentThread().interrupt();
877 }
878 }
879 Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
880
881 if (puk == null) {
882 mSimCard.supplyPin(pin, callback);
883 } else {
884 mSimCard.supplyPuk(puk, pin, callback);
885 }
886
887 while (!mDone) {
888 try {
889 Log.d(LOG_TAG, "wait for done");
890 wait();
891 } catch (InterruptedException e) {
892 // Restore the interrupted status
893 Thread.currentThread().interrupt();
894 }
895 }
896 Log.d(LOG_TAG, "done");
Wink Saville9de0f752013-10-22 19:04:03 -0700897 int[] resultArray = new int[2];
898 resultArray[0] = mResult;
899 resultArray[1] = mRetryCount;
900 return resultArray;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700901 }
902 }
903
904 public void updateServiceLocation() {
Wink Saville36469e72014-06-11 15:17:00 -0700905 updateServiceLocationUsingSubId(getDefaultSubscription());
906
907 }
908
909 public void updateServiceLocationUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700910 // No permission check needed here: this call is harmless, and it's
911 // needed for the ServiceState.requestStateUpdate() call (which is
912 // already intentionally exposed to 3rd parties.)
Wink Saville36469e72014-06-11 15:17:00 -0700913 getPhone(subId).updateServiceLocation();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700914 }
915
916 public boolean isRadioOn() {
Wink Saville36469e72014-06-11 15:17:00 -0700917 return isRadioOnUsingSubId(getDefaultSubscription());
918 }
919
920 public boolean isRadioOnUsingSubId(long subId) {
921 return getPhone(subId).getServiceState().getState() != ServiceState.STATE_POWER_OFF;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700922 }
923
924 public void toggleRadioOnOff() {
Wink Saville36469e72014-06-11 15:17:00 -0700925 toggleRadioOnOffUsingSubId(getDefaultSubscription());
926
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700927 }
Wink Saville36469e72014-06-11 15:17:00 -0700928
929 public void toggleRadioOnOffUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700930 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700931 getPhone(subId).setRadioPower(!isRadioOnUsingSubId(subId));
932 }
933
934 public boolean setRadio(boolean turnOn) {
935 return setRadioUsingSubId(getDefaultSubscription(), turnOn);
936 }
937
938 public boolean setRadioUsingSubId(long subId, boolean turnOn) {
939 enforceModifyPermission();
940 if ((getPhone(subId).getServiceState().getState() !=
941 ServiceState.STATE_POWER_OFF) != turnOn) {
942 toggleRadioOnOffUsingSubId(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700943 }
944 return true;
945 }
Wink Saville36469e72014-06-11 15:17:00 -0700946
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700947 public boolean setRadioPower(boolean turnOn) {
Wink Saville36469e72014-06-11 15:17:00 -0700948 return setRadioPowerUsingSubId(getDefaultSubscription(), turnOn);
949 }
950
951 public boolean setRadioPowerUsingSubId(long subId, boolean turnOn) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700952 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700953 getPhone(subId).setRadioPower(turnOn);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700954 return true;
955 }
956
Wink Saville36469e72014-06-11 15:17:00 -0700957 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700958 public boolean enableDataConnectivity() {
959 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700960 long subId = SubscriptionManager.getDefaultDataSubId();
961 getPhone(subId).setDataEnabled(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700962 return true;
963 }
964
Wink Saville36469e72014-06-11 15:17:00 -0700965 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700966 public boolean disableDataConnectivity() {
967 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700968 long subId = SubscriptionManager.getDefaultDataSubId();
969 getPhone(subId).setDataEnabled(false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700970 return true;
971 }
972
Wink Saville36469e72014-06-11 15:17:00 -0700973 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700974 public boolean isDataConnectivityPossible() {
Wink Saville36469e72014-06-11 15:17:00 -0700975 long subId = SubscriptionManager.getDefaultDataSubId();
976 return getPhone(subId).isDataConnectivityPossible();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700977 }
978
979 public boolean handlePinMmi(String dialString) {
Wink Saville36469e72014-06-11 15:17:00 -0700980 return handlePinMmiUsingSubId(getDefaultSubscription(), dialString);
981 }
982
983 public boolean handlePinMmiUsingSubId(long subId, String dialString) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700984 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700985 return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700986 }
987
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700988 public int getCallState() {
Wink Saville36469e72014-06-11 15:17:00 -0700989 return getCallStateUsingSubId(getDefaultSubscription());
990 }
991
992 public int getCallStateUsingSubId(long subId) {
993 return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700994 }
995
996 public int getDataState() {
Wink Saville36469e72014-06-11 15:17:00 -0700997 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
998 return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700999 }
1000
1001 public int getDataActivity() {
Wink Saville36469e72014-06-11 15:17:00 -07001002 Phone phone = getPhone(SubscriptionManager.getDefaultDataSubId());
1003 return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001004 }
1005
1006 @Override
1007 public Bundle getCellLocation() {
1008 try {
1009 mApp.enforceCallingOrSelfPermission(
1010 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1011 } catch (SecurityException e) {
1012 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1013 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1014 // is the weaker precondition
1015 mApp.enforceCallingOrSelfPermission(
1016 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1017 }
1018
Jake Hambye994d462014-02-03 13:10:13 -08001019 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001020 if (DBG_LOC) log("getCellLocation: is active user");
1021 Bundle data = new Bundle();
1022 mPhone.getCellLocation().fillInNotifierBundle(data);
1023 return data;
1024 } else {
1025 if (DBG_LOC) log("getCellLocation: suppress non-active user");
1026 return null;
1027 }
1028 }
1029
1030 @Override
1031 public void enableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001032 enableLocationUpdatesUsingSubId(getDefaultSubscription());
1033 }
1034
1035 public void enableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001036 mApp.enforceCallingOrSelfPermission(
1037 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001038 getPhone(subId).enableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001039 }
1040
1041 @Override
1042 public void disableLocationUpdates() {
Wink Saville36469e72014-06-11 15:17:00 -07001043 disableLocationUpdatesUsingSubId(getDefaultSubscription());
1044 }
1045
1046 public void disableLocationUpdatesUsingSubId(long subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001047 mApp.enforceCallingOrSelfPermission(
1048 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001049 getPhone(subId).disableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001050 }
1051
1052 @Override
1053 @SuppressWarnings("unchecked")
1054 public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1055 try {
1056 mApp.enforceCallingOrSelfPermission(
1057 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1058 } catch (SecurityException e) {
1059 // If we have ACCESS_FINE_LOCATION permission, skip the check
1060 // for ACCESS_COARSE_LOCATION
1061 // A failure should throw the SecurityException from
1062 // ACCESS_COARSE_LOCATION since this is the weaker precondition
1063 mApp.enforceCallingOrSelfPermission(
1064 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1065 }
1066
1067 if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1068 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1069 return null;
1070 }
Jake Hambye994d462014-02-03 13:10:13 -08001071 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001072 if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1073
1074 ArrayList<NeighboringCellInfo> cells = null;
1075
1076 try {
1077 cells = (ArrayList<NeighboringCellInfo>) sendRequest(
Wink Saville36469e72014-06-11 15:17:00 -07001078 CMD_HANDLE_NEIGHBORING_CELL, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001079 } catch (RuntimeException e) {
Wink Saville36469e72014-06-11 15:17:00 -07001080 Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001081 }
1082 return cells;
1083 } else {
1084 if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1085 return null;
1086 }
1087 }
1088
1089
1090 @Override
1091 public List<CellInfo> getAllCellInfo() {
1092 try {
1093 mApp.enforceCallingOrSelfPermission(
1094 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1095 } catch (SecurityException e) {
1096 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1097 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1098 // is the weaker precondition
1099 mApp.enforceCallingOrSelfPermission(
1100 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1101 }
1102
Jake Hambye994d462014-02-03 13:10:13 -08001103 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001104 if (DBG_LOC) log("getAllCellInfo: is active user");
1105 return mPhone.getAllCellInfo();
1106 } else {
1107 if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1108 return null;
1109 }
1110 }
1111
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -07001112 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001113 public void setCellInfoListRate(int rateInMillis) {
1114 mPhone.setCellInfoListRate(rateInMillis);
1115 }
1116
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001117 //
1118 // Internal helper methods.
1119 //
1120
Jake Hambye994d462014-02-03 13:10:13 -08001121 private static boolean checkIfCallerIsSelfOrForegroundUser() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001122 boolean ok;
1123
1124 boolean self = Binder.getCallingUid() == Process.myUid();
1125 if (!self) {
1126 // Get the caller's user id then clear the calling identity
1127 // which will be restored in the finally clause.
1128 int callingUser = UserHandle.getCallingUserId();
1129 long ident = Binder.clearCallingIdentity();
1130
1131 try {
1132 // With calling identity cleared the current user is the foreground user.
1133 int foregroundUser = ActivityManager.getCurrentUser();
1134 ok = (foregroundUser == callingUser);
1135 if (DBG_LOC) {
1136 log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1137 + " callingUser=" + callingUser + " ok=" + ok);
1138 }
1139 } catch (Exception ex) {
1140 if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1141 ok = false;
1142 } finally {
1143 Binder.restoreCallingIdentity(ident);
1144 }
1145 } else {
1146 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1147 ok = true;
1148 }
1149 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1150 return ok;
1151 }
1152
1153 /**
1154 * Make sure the caller has the READ_PHONE_STATE permission.
1155 *
1156 * @throws SecurityException if the caller does not have the required permission
1157 */
1158 private void enforceReadPermission() {
1159 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
1160 }
1161
1162 /**
1163 * Make sure the caller has the MODIFY_PHONE_STATE permission.
1164 *
1165 * @throws SecurityException if the caller does not have the required permission
1166 */
1167 private void enforceModifyPermission() {
1168 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1169 }
1170
1171 /**
Junda Liua2e36012014-07-09 18:30:01 -07001172 * Make sure either system app or the caller has carrier privilege.
1173 *
1174 * @throws SecurityException if the caller does not have the required permission/privilege
1175 */
1176 private void enforceModifyPermissionOrCarrierPrivilege() {
1177 try {
1178 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1179 } catch (SecurityException e) {
1180 log("No modify permission, check carrier privilege next.");
1181 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1182 loge("No Carrier Privilege.");
1183 throw new SecurityException("No modify permission or carrier privilege.");
1184 }
1185 }
1186 }
1187
1188 /**
1189 * Make sure the caller has carrier privilege.
1190 *
1191 * @throws SecurityException if the caller does not have the required permission
1192 */
1193 private void enforceCarrierPrivilege() {
1194 if (hasCarrierPrivileges() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1195 loge("No Carrier Privilege.");
1196 throw new SecurityException("No Carrier Privilege.");
1197 }
1198 }
1199
1200 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001201 * Make sure the caller has the CALL_PHONE permission.
1202 *
1203 * @throws SecurityException if the caller does not have the required permission
1204 */
1205 private void enforceCallPermission() {
1206 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1207 }
1208
Shishir Agrawal566b7612013-10-28 14:41:00 -07001209 /**
Gabriel Peal36ebb0d2014-03-20 09:20:43 -07001210 * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1211 *
1212 * @throws SecurityException if the caller does not have the required permission
1213 */
1214 private void enforcePrivilegedPhoneStatePermission() {
1215 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1216 null);
1217 }
1218
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001219 private String createTelUrl(String number) {
1220 if (TextUtils.isEmpty(number)) {
1221 return null;
1222 }
1223
Jake Hambye994d462014-02-03 13:10:13 -08001224 return "tel:" + number;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001225 }
1226
Ihab Awadf9e92732013-12-05 18:02:52 -08001227 private static void log(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001228 Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1229 }
1230
Ihab Awadf9e92732013-12-05 18:02:52 -08001231 private static void loge(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001232 Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1233 }
1234
1235 public int getActivePhoneType() {
Wink Saville36469e72014-06-11 15:17:00 -07001236 return getActivePhoneTypeUsingSubId(getDefaultSubscription());
1237 }
1238
1239 public int getActivePhoneTypeUsingSubId(long subId) {
1240 return getPhone(subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001241 }
1242
1243 /**
1244 * Returns the CDMA ERI icon index to display
1245 */
1246 public int getCdmaEriIconIndex() {
Wink Saville36469e72014-06-11 15:17:00 -07001247 return getCdmaEriIconIndexUsingSubId(getDefaultSubscription());
1248
1249 }
1250
1251 public int getCdmaEriIconIndexUsingSubId(long subId) {
1252 return getPhone(subId).getCdmaEriIconIndex();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001253 }
1254
1255 /**
1256 * Returns the CDMA ERI icon mode,
1257 * 0 - ON
1258 * 1 - FLASHING
1259 */
1260 public int getCdmaEriIconMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001261 return getCdmaEriIconModeUsingSubId(getDefaultSubscription());
1262 }
1263
1264 public int getCdmaEriIconModeUsingSubId(long subId) {
1265 return getPhone(subId).getCdmaEriIconMode();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001266 }
1267
1268 /**
1269 * Returns the CDMA ERI text,
1270 */
1271 public String getCdmaEriText() {
Wink Saville36469e72014-06-11 15:17:00 -07001272 return getCdmaEriTextUsingSubId(getDefaultSubscription());
1273 }
1274
1275 public String getCdmaEriTextUsingSubId(long subId) {
1276 return getPhone(subId).getCdmaEriText();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001277 }
1278
1279 /**
1280 * Returns true if CDMA provisioning needs to run.
1281 */
1282 public boolean needsOtaServiceProvisioning() {
1283 return mPhone.needsOtaServiceProvisioning();
1284 }
1285
1286 /**
1287 * Returns the unread count of voicemails
1288 */
1289 public int getVoiceMessageCount() {
Wink Saville36469e72014-06-11 15:17:00 -07001290 return getVoiceMessageCountUsingSubId(getDefaultSubscription());
1291 }
1292
1293 /**
1294 * Returns the unread count of voicemails for a subId
1295 */
1296 public int getVoiceMessageCountUsingSubId( long subId) {
1297 return getPhone(subId).getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001298 }
1299
1300 /**
1301 * Returns the data network type
1302 *
1303 * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1304 */
1305 @Override
1306 public int getNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001307 return getNetworkTypeUsingSubId(getDefaultSubscription());
1308 }
1309
1310 /**
1311 * Returns the network type for a subId
1312 */
1313 @Override
1314 public int getNetworkTypeUsingSubId(long subId) {
1315 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001316 }
1317
1318 /**
1319 * Returns the data network type
1320 */
1321 @Override
1322 public int getDataNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001323 return getDataNetworkTypeUsingSubId(getDefaultSubscription());
1324 }
1325
1326 /**
1327 * Returns the data network type for a subId
1328 */
1329 @Override
1330 public int getDataNetworkTypeUsingSubId(long subId) {
1331 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001332 }
1333
1334 /**
1335 * Returns the data network type
1336 */
1337 @Override
1338 public int getVoiceNetworkType() {
Wink Saville36469e72014-06-11 15:17:00 -07001339 return getVoiceNetworkTypeUsingSubId(getDefaultSubscription());
1340 }
1341
1342 /**
1343 * Returns the Voice network type for a subId
1344 */
1345 @Override
1346 public int getVoiceNetworkTypeUsingSubId(long subId) {
1347 return getPhone(subId).getServiceState().getVoiceNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001348 }
1349
1350 /**
1351 * @return true if a ICC card is present
1352 */
1353 public boolean hasIccCard() {
Wink Saville36469e72014-06-11 15:17:00 -07001354 // FIXME Make changes to pass defaultSimId of type int
1355 return hasIccCardUsingSlotId(getDefaultSubscription());
1356 }
1357
1358 /**
1359 * @return true if a ICC card is present for a slotId
1360 */
1361 public boolean hasIccCardUsingSlotId(long slotId) {
1362 return getPhone(slotId).getIccCard().hasIccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001363 }
1364
1365 /**
1366 * Return if the current radio is LTE on CDMA. This
1367 * is a tri-state return value as for a period of time
1368 * the mode may be unknown.
1369 *
1370 * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
Jake Hambye994d462014-02-03 13:10:13 -08001371 * or {@link Phone#LTE_ON_CDMA_TRUE}
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001372 */
1373 public int getLteOnCdmaMode() {
Wink Saville36469e72014-06-11 15:17:00 -07001374 return getLteOnCdmaModeUsingSubId(getDefaultSubscription());
1375 }
1376
1377 public int getLteOnCdmaModeUsingSubId(long subId) {
1378 return getPhone(subId).getLteOnCdmaMode();
1379 }
1380
1381 public void setPhone(Phone phone) {
1382 mPhone = phone;
1383 }
1384
1385 /**
1386 * {@hide}
1387 * Returns Default subId, 0 in the case of single standby.
1388 */
1389 private long getDefaultSubscription() {
1390 return SubscriptionManager.getDefaultSubId();
1391 }
1392
1393 private long getPreferredVoiceSubscription() {
1394 return SubscriptionManager.getDefaultVoiceSubId();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001395 }
Ihab Awadf2177b72013-11-25 13:33:23 -08001396
1397 /**
1398 * @see android.telephony.TelephonyManager.WifiCallingChoices
1399 */
1400 public int getWhenToMakeWifiCalls() {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001401 return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1402 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
Ihab Awadf2177b72013-11-25 13:33:23 -08001403 }
1404
1405 /**
1406 * @see android.telephony.TelephonyManager.WifiCallingChoices
1407 */
1408 public void setWhenToMakeWifiCalls(int preference) {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001409 if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1410 Settings.System.putInt(mPhone.getContext().getContentResolver(),
1411 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
Ihab Awadf9e92732013-12-05 18:02:52 -08001412 }
1413
Sailesh Nepald1e68152013-12-12 19:08:02 -08001414 private static int getWhenToMakeWifiCallsDefaultPreference() {
1415 // TODO(sail): Use a build property to choose this value.
Evan Charlton9829e882013-12-19 15:30:38 -08001416 return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
Ihab Awadf2177b72013-11-25 13:33:23 -08001417 }
Shishir Agrawal69f68122013-12-16 17:25:49 -08001418
Shishir Agrawal566b7612013-10-28 14:41:00 -07001419 @Override
1420 public int iccOpenLogicalChannel(String AID) {
Junda Liua2e36012014-07-09 18:30:01 -07001421 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001422
1423 if (DBG) log("iccOpenLogicalChannel: " + AID);
1424 Integer channel = (Integer)sendRequest(CMD_OPEN_CHANNEL, AID);
1425 if (DBG) log("iccOpenLogicalChannel: " + channel);
Jake Hambye994d462014-02-03 13:10:13 -08001426 return channel;
Shishir Agrawal566b7612013-10-28 14:41:00 -07001427 }
1428
1429 @Override
1430 public boolean iccCloseLogicalChannel(int channel) {
Junda Liua2e36012014-07-09 18:30:01 -07001431 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001432
1433 if (DBG) log("iccCloseLogicalChannel: " + channel);
1434 if (channel < 0) {
1435 return false;
1436 }
Jake Hambye994d462014-02-03 13:10:13 -08001437 Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
Shishir Agrawal566b7612013-10-28 14:41:00 -07001438 if (DBG) log("iccCloseLogicalChannel: " + success);
1439 return success;
1440 }
1441
1442 @Override
1443 public String iccTransmitApduLogicalChannel(int channel, int cla,
1444 int command, int p1, int p2, int p3, String data) {
Junda Liua2e36012014-07-09 18:30:01 -07001445 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001446
1447 if (DBG) {
1448 log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1449 " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1450 " data=" + data);
1451 }
1452
1453 if (channel < 0) {
1454 return "";
1455 }
1456
1457 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU,
1458 new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1459 if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1460
1461 // If the payload is null, there was an error. Indicate that by returning
1462 // an empty string.
1463 if (response.payload == null) {
1464 return "";
1465 }
1466
1467 // Append the returned status code to the end of the response payload.
1468 String s = Integer.toHexString(
1469 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1470 s = IccUtils.bytesToHexString(response.payload) + s;
1471 return s;
1472 }
Jake Hambye994d462014-02-03 13:10:13 -08001473
Evan Charltonc66da362014-05-16 14:06:40 -07001474 @Override
1475 public String sendEnvelopeWithStatus(String content) {
Junda Liua2e36012014-07-09 18:30:01 -07001476 enforceModifyPermissionOrCarrierPrivilege();
Evan Charltonc66da362014-05-16 14:06:40 -07001477
1478 IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
1479 if (response.payload == null) {
1480 return "";
1481 }
1482
1483 // Append the returned status code to the end of the response payload.
1484 String s = Integer.toHexString(
1485 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1486 s = IccUtils.bytesToHexString(response.payload) + s;
1487 return s;
1488 }
1489
Jake Hambye994d462014-02-03 13:10:13 -08001490 /**
1491 * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1492 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1493 *
1494 * @param itemID the ID of the item to read
1495 * @return the NV item as a String, or null on error.
1496 */
1497 @Override
1498 public String nvReadItem(int itemID) {
Junda Liua2e36012014-07-09 18:30:01 -07001499 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001500 if (DBG) log("nvReadItem: item " + itemID);
1501 String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
1502 if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
1503 return value;
1504 }
1505
1506 /**
1507 * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1508 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1509 *
1510 * @param itemID the ID of the item to read
1511 * @param itemValue the value to write, as a String
1512 * @return true on success; false on any failure
1513 */
1514 @Override
1515 public boolean nvWriteItem(int itemID, String itemValue) {
Junda Liua2e36012014-07-09 18:30:01 -07001516 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001517 if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
1518 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
1519 new Pair<Integer, String>(itemID, itemValue));
1520 if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
1521 return success;
1522 }
1523
1524 /**
1525 * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
1526 * Used for device configuration by some CDMA operators.
1527 *
1528 * @param preferredRoamingList byte array containing the new PRL
1529 * @return true on success; false on any failure
1530 */
1531 @Override
1532 public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
Junda Liua2e36012014-07-09 18:30:01 -07001533 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001534 if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
1535 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
1536 if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
1537 return success;
1538 }
1539
1540 /**
1541 * Perform the specified type of NV config reset.
1542 * Used for device configuration by some CDMA operators.
1543 *
1544 * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
1545 * @return true on success; false on any failure
1546 */
1547 @Override
1548 public boolean nvResetConfig(int resetType) {
Junda Liua2e36012014-07-09 18:30:01 -07001549 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001550 if (DBG) log("nvResetConfig: type " + resetType);
1551 Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
1552 if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
1553 return success;
1554 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001555
1556 /**
Wink Saville36469e72014-06-11 15:17:00 -07001557 * {@hide}
1558 * Returns Default sim, 0 in the case of single standby.
1559 */
1560 public int getDefaultSim() {
1561 //TODO Need to get it from Telephony Devcontroller
1562 return 0;
1563 }
1564
1565 public String[] getPcscfAddress() {
1566 enforceReadPermission();
1567 return mPhone.getPcscfAddress();
1568 }
1569
1570 public void setImsRegistrationState(boolean registered) {
1571 enforceModifyPermission();
1572 mPhone.setImsRegistrationState(registered);
1573 }
1574
1575 /**
Junda Liu84d15a22014-07-02 11:21:04 -07001576 * Get the calculated preferred network type.
1577 * Used for debugging incorrect network type.
1578 *
1579 * @return the preferred network type, defined in RILConstants.java.
1580 */
1581 @Override
1582 public int getCalculatedPreferredNetworkType() {
1583 enforceReadPermission();
1584 return PhoneFactory.calculatePreferredNetworkType(mPhone.getContext());
1585 }
1586
1587 /**
Jake Hamby7c27be32014-03-03 13:25:59 -08001588 * Get the preferred network type.
1589 * Used for device configuration by some CDMA operators.
1590 *
1591 * @return the preferred network type, defined in RILConstants.java.
1592 */
1593 @Override
1594 public int getPreferredNetworkType() {
Junda Liua2e36012014-07-09 18:30:01 -07001595 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001596 if (DBG) log("getPreferredNetworkType");
1597 int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null);
1598 int networkType = (result != null ? result[0] : -1);
1599 if (DBG) log("getPreferredNetworkType: " + networkType);
1600 return networkType;
1601 }
1602
1603 /**
1604 * Set the preferred network type.
1605 * Used for device configuration by some CDMA operators.
1606 *
1607 * @param networkType the preferred network type, defined in RILConstants.java.
1608 * @return true on success; false on any failure.
1609 */
1610 @Override
1611 public boolean setPreferredNetworkType(int networkType) {
Junda Liua2e36012014-07-09 18:30:01 -07001612 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001613 if (DBG) log("setPreferredNetworkType: type " + networkType);
1614 Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType);
1615 if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
1616 return success;
1617 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001618
1619 /**
Junda Liu787bc7e2014-06-30 13:38:02 -07001620 * Set the CDMA subscription source.
1621 * Used for device supporting both NV and RUIM for CDMA.
1622 *
1623 * @param subscriptionType the subscription type, 0 for RUIM, 1 for NV.
1624 * @return true on success; false on any failure.
1625 */
1626 @Override
1627 public boolean setCdmaSubscription(int subscriptionType) {
Junda Liua2e36012014-07-09 18:30:01 -07001628 enforceModifyPermissionOrCarrierPrivilege();
Junda Liu787bc7e2014-06-30 13:38:02 -07001629 if (DBG) log("setCdmaSubscription: type " + subscriptionType);
1630 if (subscriptionType != mPhone.CDMA_SUBSCRIPTION_RUIM_SIM &&
1631 subscriptionType != mPhone.CDMA_SUBSCRIPTION_NV) {
1632 loge("setCdmaSubscription: unsupported subscriptionType.");
1633 return false;
1634 }
1635 Boolean success = (Boolean) sendRequest(CMD_SET_CDMA_SUBSCRIPTION, subscriptionType);
1636 if (DBG) log("setCdmaSubscription: " + (success ? "ok" : "fail"));
1637 if (success) {
1638 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1639 Settings.Global.CDMA_SUBSCRIPTION_MODE, subscriptionType);
1640 }
1641 return success;
1642 }
1643
1644 /**
Robert Greenwalted86e582014-05-21 20:03:20 -07001645 * Set mobile data enabled
1646 * Used by the user through settings etc to turn on/off mobile data
1647 *
1648 * @param enable {@code true} turn turn data on, else {@code false}
1649 */
1650 @Override
1651 public void setDataEnabled(boolean enable) {
1652 enforceModifyPermission();
1653 mPhone.setDataEnabled(enable);
1654 }
1655
1656 /**
Robert Greenwalt646120a2014-05-23 11:54:03 -07001657 * Get whether mobile data is enabled.
1658 *
1659 * Note that this used to be available from ConnectivityService, gated by
1660 * ACCESS_NETWORK_STATE permission, so this will accept either that or
1661 * our MODIFY_PHONE_STATE.
Robert Greenwalted86e582014-05-21 20:03:20 -07001662 *
1663 * @return {@code true} if data is enabled else {@code false}
1664 */
1665 @Override
1666 public boolean getDataEnabled() {
Robert Greenwalt646120a2014-05-23 11:54:03 -07001667 try {
1668 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
1669 null);
1670 } catch (Exception e) {
1671 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
1672 null);
1673 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001674 return mPhone.getDataEnabled();
1675 }
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001676
1677 @Override
1678 public int hasCarrierPrivileges() {
1679 PackageManager packageManager = mPhone.getContext().getPackageManager();
1680 String[] packages = packageManager.getPackagesForUid(Binder.getCallingUid());
1681
1682 for (String pkg : packages) {
1683 try {
1684 PackageInfo pInfo = packageManager.getPackageInfo(pkg,
1685 PackageManager.GET_SIGNATURES);
1686 Signature[] signatures = pInfo.signatures;
1687 for (Signature sig : signatures) {
1688 int hasAccess = UiccController.getInstance().getUiccCard().hasCarrierPrivileges(
1689 sig, pInfo.packageName);
1690 if (hasAccess != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) {
1691 return hasAccess;
1692 }
1693 }
1694 } catch (PackageManager.NameNotFoundException ex) {
1695 loge("NameNotFoundException: " + ex);
1696 continue;
1697 }
1698 }
1699 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
1700 }
Junda Liu29340342014-07-10 15:23:27 -07001701
1702 @Override
Shishir Agrawal6d5a2852014-07-11 16:32:57 -07001703 public int checkCarrierPrivilegesForPackage(String pkgname) {
Junda Liu29340342014-07-10 15:23:27 -07001704 PackageManager packageManager = mPhone.getContext().getPackageManager();
1705 try {
1706 PackageInfo pInfo = packageManager.getPackageInfo(pkgname,
1707 PackageManager.GET_SIGNATURES);
1708 Signature[] signatures = pInfo.signatures;
1709 for (Signature sig : signatures) {
1710 int hasAccess = UiccController.getInstance().getUiccCard().hasCarrierPrivileges(
1711 sig, pInfo.packageName);
1712 if (hasAccess != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) {
1713 return hasAccess;
1714 }
1715 }
1716 } catch (PackageManager.NameNotFoundException ex) {
1717 loge("NameNotFoundException: " + ex);
1718 }
1719 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
1720 }
Derek Tan89e89d42014-07-08 17:00:10 -07001721
1722 @Override
1723 public void enableSimplifiedNetworkSettings(long subId, boolean enable) {
1724 enforceModifyPermission();
1725 if (enable) {
1726 mSimplifiedNetworkSettings.add(subId);
1727 } else {
1728 mSimplifiedNetworkSettings.remove(subId);
1729 }
1730 }
1731
1732 @Override
1733 public boolean getSimplifiedNetworkSettingsEnabled(long subId) {
1734 enforceReadPermission();
1735 return mSimplifiedNetworkSettings.contains(subId);
1736 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001737}