blob: b97f3b6511200265a65ccfb7abf2fcec3ab6a34e [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.phone;
18
19import android.app.ActivityManager;
20import android.app.AppOpsManager;
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -070021import android.content.ComponentName;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070022import android.content.Context;
23import android.content.Intent;
Derek Tan97ebb422014-09-05 16:55:38 -070024import android.content.SharedPreferences;
Shishir Agrawal60f9c952014-06-23 12:00:43 -070025import android.content.pm.PackageManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070026import android.net.Uri;
27import android.os.AsyncResult;
28import android.os.Binder;
29import android.os.Bundle;
30import android.os.Handler;
31import android.os.Looper;
32import android.os.Message;
33import android.os.Process;
34import android.os.ServiceManager;
35import android.os.UserHandle;
Derek Tan97ebb422014-09-05 16:55:38 -070036import android.preference.PreferenceManager;
Ihab Awadf2177b72013-11-25 13:33:23 -080037import android.provider.Settings;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070038import android.telephony.CellInfo;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -070039import android.telephony.IccOpenLogicalChannelResponse;
Jake Hambye994d462014-02-03 13:10:13 -080040import android.telephony.NeighboringCellInfo;
Wink Saville5d475dd2014-10-17 15:00:58 -070041import android.telephony.RadioAccessFamily;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070042import android.telephony.ServiceState;
Wink Saville0f3b5fc2014-11-11 08:40:49 -080043import android.telephony.SubscriptionInfo;
Jeff Sharkey85190e62014-12-05 09:40:12 -080044import 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;
Jeff Sharkey85190e62014-12-05 09:40:12 -080047import android.util.ArrayMap;
48import android.util.ArraySet;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070049import android.util.Log;
Jake Hambye994d462014-02-03 13:10:13 -080050import android.util.Pair;
Jeff Sharkey85190e62014-12-05 09:40:12 -080051import android.util.Slog;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070052
Andrew Lee312e8172014-10-23 17:01:36 -070053import com.android.ims.ImsManager;
Shishir Agrawal566b7612013-10-28 14:41:00 -070054import com.android.internal.telephony.CallManager;
55import com.android.internal.telephony.CommandException;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070056import com.android.internal.telephony.DefaultPhoneNotifier;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070057import com.android.internal.telephony.ITelephony;
Jake Hambye994d462014-02-03 13:10:13 -080058import com.android.internal.telephony.IccCard;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070059import com.android.internal.telephony.Phone;
Wink Saville36469e72014-06-11 15:17:00 -070060import com.android.internal.telephony.PhoneFactory;
Wink Saville5d475dd2014-10-17 15:00:58 -070061import com.android.internal.telephony.ProxyController;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070062import com.android.internal.telephony.PhoneConstants;
Wink Savilleac1bdfd2014-11-20 23:04:44 -080063import com.android.internal.telephony.SubscriptionController;
Shishir Agrawal566b7612013-10-28 14:41:00 -070064import com.android.internal.telephony.uicc.IccIoResult;
65import com.android.internal.telephony.uicc.IccUtils;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -070066import com.android.internal.telephony.uicc.UiccCard;
Shishir 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;
Jeff Sharkey85190e62014-12-05 09:40:12 -080073import java.util.Arrays;
Jake Hambye994d462014-02-03 13:10:13 -080074import java.util.List;
Jeff Sharkey85190e62014-12-05 09:40:12 -080075import java.util.Map;
76import java.util.Objects;
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;
Jeff Sharkey85190e62014-12-05 09:40:12 -080085 private static final boolean DBG_MERGE = false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070086
87 // Message codes used with mMainThreadHandler
88 private static final int CMD_HANDLE_PIN_MMI = 1;
89 private static final int CMD_HANDLE_NEIGHBORING_CELL = 2;
90 private static final int EVENT_NEIGHBORING_CELL_DONE = 3;
91 private static final int CMD_ANSWER_RINGING_CALL = 4;
92 private static final int CMD_END_CALL = 5; // not used yet
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -070093 private static final int CMD_TRANSMIT_APDU_LOGICAL_CHANNEL = 7;
94 private static final int EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE = 8;
Shishir Agrawal566b7612013-10-28 14:41:00 -070095 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;
Derek Tan6b088ee2014-09-05 14:15:18 -0700113 private static final int CMD_INVOKE_OEM_RIL_REQUEST_RAW = 27;
114 private static final int EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE = 28;
115 private static final int CMD_TRANSMIT_APDU_BASIC_CHANNEL = 29;
116 private static final int EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE = 30;
117 private static final int CMD_EXCHANGE_SIM_IO = 31;
118 private static final int EVENT_EXCHANGE_SIM_IO_DONE = 32;
Shishir Agrawal76d5da92014-11-09 16:17:25 -0800119 private static final int CMD_SET_VOICEMAIL_NUMBER = 33;
120 private static final int EVENT_SET_VOICEMAIL_NUMBER_DONE = 34;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700121
122 /** The singleton instance. */
123 private static PhoneInterfaceManager sInstance;
124
Wink Saville3ab207e2014-11-20 13:07:20 -0800125 private PhoneGlobals mApp;
126 private Phone mPhone;
127 private CallManager mCM;
128 private AppOpsManager mAppOps;
129 private MainThreadHandler mMainThreadHandler;
Wink Savilleac1bdfd2014-11-20 23:04:44 -0800130 private SubscriptionController mSubscriptionController;
Wink Saville3ab207e2014-11-20 13:07:20 -0800131 private SharedPreferences mTelephonySharedPreferences;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700132
Derek Tan97ebb422014-09-05 16:55:38 -0700133 private static final String PREF_CARRIERS_ALPHATAG_PREFIX = "carrier_alphtag_";
134 private static final String PREF_CARRIERS_NUMBER_PREFIX = "carrier_number_";
Jeff Sharkey85190e62014-12-05 09:40:12 -0800135 private static final String PREF_CARRIERS_SUBSCRIBER_PREFIX = "carrier_subscriber_";
Andrew Leedf14ead2014-10-17 14:22:52 -0700136 private static final String PREF_ENABLE_VIDEO_CALLING = "enable_video_calling";
Derek Tan89e89d42014-07-08 17:00:10 -0700137
138 /**
Shishir Agrawal566b7612013-10-28 14:41:00 -0700139 * A request object to use for transmitting data to an ICC.
140 */
141 private static final class IccAPDUArgument {
142 public int channel, cla, command, p1, p2, p3;
143 public String data;
144
145 public IccAPDUArgument(int channel, int cla, int command,
146 int p1, int p2, int p3, String data) {
147 this.channel = channel;
148 this.cla = cla;
149 this.command = command;
150 this.p1 = p1;
151 this.p2 = p2;
152 this.p3 = p3;
153 this.data = data;
154 }
155 }
156
157 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700158 * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
159 * request after sending. The main thread will notify the request when it is complete.
160 */
161 private static final class MainThreadRequest {
162 /** The argument to use for the request */
163 public Object argument;
164 /** The result of the request that is run on the main thread */
165 public Object result;
Shishir Agrawal76d5da92014-11-09 16:17:25 -0800166 /** The subscriber id that this request applies to. Null if default. */
167 public Integer subId;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700168
169 public MainThreadRequest(Object argument) {
170 this.argument = argument;
171 }
Shishir Agrawal76d5da92014-11-09 16:17:25 -0800172
173 public MainThreadRequest(Object argument, Integer subId) {
174 this.argument = argument;
175 this.subId = subId;
176 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700177 }
178
Sailesh Nepalcc0375f2013-11-13 09:15:18 -0800179 private static final class IncomingThirdPartyCallArgs {
180 public final ComponentName component;
181 public final String callId;
182 public final String callerDisplayName;
183
184 public IncomingThirdPartyCallArgs(ComponentName component, String callId,
185 String callerDisplayName) {
186 this.component = component;
187 this.callId = callId;
188 this.callerDisplayName = callerDisplayName;
189 }
190 }
191
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700192 /**
193 * A handler that processes messages on the main thread in the phone process. Since many
194 * of the Phone calls are not thread safe this is needed to shuttle the requests from the
195 * inbound binder threads to the main thread in the phone process. The Binder thread
196 * may provide a {@link MainThreadRequest} object in the msg.obj field that they are waiting
197 * on, which will be notified when the operation completes and will contain the result of the
198 * request.
199 *
200 * <p>If a MainThreadRequest object is provided in the msg.obj field,
201 * note that request.result must be set to something non-null for the calling thread to
202 * unblock.
203 */
204 private final class MainThreadHandler extends Handler {
205 @Override
206 public void handleMessage(Message msg) {
207 MainThreadRequest request;
208 Message onCompleted;
209 AsyncResult ar;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700210 UiccCard uiccCard = UiccController.getInstance().getUiccCard();
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700211 IccAPDUArgument iccArgument;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700212
213 switch (msg.what) {
214 case CMD_HANDLE_PIN_MMI:
215 request = (MainThreadRequest) msg.obj;
Jake Hambye994d462014-02-03 13:10:13 -0800216 request.result = mPhone.handlePinMmi((String) request.argument);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700217 // Wake up the requesting thread
218 synchronized (request) {
219 request.notifyAll();
220 }
221 break;
222
223 case CMD_HANDLE_NEIGHBORING_CELL:
224 request = (MainThreadRequest) msg.obj;
225 onCompleted = obtainMessage(EVENT_NEIGHBORING_CELL_DONE,
226 request);
227 mPhone.getNeighboringCids(onCompleted);
228 break;
229
230 case EVENT_NEIGHBORING_CELL_DONE:
231 ar = (AsyncResult) msg.obj;
232 request = (MainThreadRequest) ar.userObj;
233 if (ar.exception == null && ar.result != null) {
234 request.result = ar.result;
235 } else {
236 // create an empty list to notify the waiting thread
Jake Hambye994d462014-02-03 13:10:13 -0800237 request.result = new ArrayList<NeighboringCellInfo>(0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700238 }
239 // Wake up the requesting thread
240 synchronized (request) {
241 request.notifyAll();
242 }
243 break;
244
245 case CMD_ANSWER_RINGING_CALL:
Wink Saville08874612014-08-31 19:19:58 -0700246 request = (MainThreadRequest) msg.obj;
Wink Savilleb564aae2014-10-23 10:18:09 -0700247 int answer_subId = ((Integer)request.argument).intValue();
Wink Saville08874612014-08-31 19:19:58 -0700248 answerRingingCallInternal(answer_subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700249 break;
250
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700251 case CMD_END_CALL:
252 request = (MainThreadRequest) msg.obj;
Wink Savilleb564aae2014-10-23 10:18:09 -0700253 int end_subId = ((Integer)request.argument).intValue();
Wink Saville08874612014-08-31 19:19:58 -0700254 final boolean hungUp;
255 int phoneType = getPhone(end_subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700256 if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
257 // CDMA: If the user presses the Power button we treat it as
258 // ending the complete call session
Wink Saville08874612014-08-31 19:19:58 -0700259 hungUp = PhoneUtils.hangupRingingAndActive(getPhone(end_subId));
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700260 } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
261 // GSM: End the call as per the Phone state
262 hungUp = PhoneUtils.hangup(mCM);
263 } else {
264 throw new IllegalStateException("Unexpected phone type: " + phoneType);
265 }
266 if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up"));
267 request.result = hungUp;
268 // Wake up the requesting thread
269 synchronized (request) {
270 request.notifyAll();
271 }
272 break;
273
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700274 case CMD_TRANSMIT_APDU_LOGICAL_CHANNEL:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700275 request = (MainThreadRequest) msg.obj;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700276 iccArgument = (IccAPDUArgument) request.argument;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700277 if (uiccCard == null) {
278 loge("iccTransmitApduLogicalChannel: No UICC");
279 request.result = new IccIoResult(0x6F, 0, (byte[])null);
280 synchronized (request) {
281 request.notifyAll();
282 }
283 } else {
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700284 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE,
285 request);
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700286 uiccCard.iccTransmitApduLogicalChannel(
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700287 iccArgument.channel, iccArgument.cla, iccArgument.command,
288 iccArgument.p1, iccArgument.p2, iccArgument.p3, iccArgument.data,
Shishir Agrawal566b7612013-10-28 14:41:00 -0700289 onCompleted);
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700290 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700291 break;
292
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700293 case EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700294 ar = (AsyncResult) msg.obj;
295 request = (MainThreadRequest) ar.userObj;
296 if (ar.exception == null && ar.result != null) {
297 request.result = ar.result;
298 } else {
299 request.result = new IccIoResult(0x6F, 0, (byte[])null);
300 if (ar.result == null) {
301 loge("iccTransmitApduLogicalChannel: Empty response");
Jake Hambye994d462014-02-03 13:10:13 -0800302 } else if (ar.exception instanceof CommandException) {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700303 loge("iccTransmitApduLogicalChannel: CommandException: " +
Jake Hambye994d462014-02-03 13:10:13 -0800304 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700305 } else {
306 loge("iccTransmitApduLogicalChannel: Unknown exception");
307 }
308 }
309 synchronized (request) {
310 request.notifyAll();
311 }
312 break;
313
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700314 case CMD_TRANSMIT_APDU_BASIC_CHANNEL:
315 request = (MainThreadRequest) msg.obj;
316 iccArgument = (IccAPDUArgument) request.argument;
317 if (uiccCard == null) {
318 loge("iccTransmitApduBasicChannel: No UICC");
319 request.result = new IccIoResult(0x6F, 0, (byte[])null);
320 synchronized (request) {
321 request.notifyAll();
322 }
323 } else {
324 onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE,
325 request);
326 uiccCard.iccTransmitApduBasicChannel(
327 iccArgument.cla, iccArgument.command, iccArgument.p1, iccArgument.p2,
328 iccArgument.p3, iccArgument.data, onCompleted);
329 }
330 break;
331
332 case EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE:
333 ar = (AsyncResult) msg.obj;
334 request = (MainThreadRequest) ar.userObj;
335 if (ar.exception == null && ar.result != null) {
336 request.result = ar.result;
337 } else {
338 request.result = new IccIoResult(0x6F, 0, (byte[])null);
339 if (ar.result == null) {
340 loge("iccTransmitApduBasicChannel: Empty response");
341 } else if (ar.exception instanceof CommandException) {
342 loge("iccTransmitApduBasicChannel: CommandException: " +
343 ar.exception);
344 } else {
345 loge("iccTransmitApduBasicChannel: Unknown exception");
346 }
347 }
348 synchronized (request) {
349 request.notifyAll();
350 }
351 break;
352
353 case CMD_EXCHANGE_SIM_IO:
354 request = (MainThreadRequest) msg.obj;
355 iccArgument = (IccAPDUArgument) request.argument;
356 if (uiccCard == null) {
357 loge("iccExchangeSimIO: No UICC");
358 request.result = new IccIoResult(0x6F, 0, (byte[])null);
359 synchronized (request) {
360 request.notifyAll();
361 }
362 } else {
363 onCompleted = obtainMessage(EVENT_EXCHANGE_SIM_IO_DONE,
364 request);
365 uiccCard.iccExchangeSimIO(iccArgument.cla, /* fileID */
366 iccArgument.command, iccArgument.p1, iccArgument.p2, iccArgument.p3,
367 iccArgument.data, onCompleted);
368 }
369 break;
370
371 case EVENT_EXCHANGE_SIM_IO_DONE:
372 ar = (AsyncResult) msg.obj;
373 request = (MainThreadRequest) ar.userObj;
374 if (ar.exception == null && ar.result != null) {
375 request.result = ar.result;
376 } else {
377 request.result = new IccIoResult(0x6f, 0, (byte[])null);
378 }
379 synchronized (request) {
380 request.notifyAll();
381 }
382 break;
383
Derek Tan4d5e5c12014-02-04 11:54:58 -0800384 case CMD_SEND_ENVELOPE:
385 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700386 if (uiccCard == null) {
387 loge("sendEnvelopeWithStatus: No UICC");
388 request.result = new IccIoResult(0x6F, 0, (byte[])null);
389 synchronized (request) {
390 request.notifyAll();
391 }
392 } else {
393 onCompleted = obtainMessage(EVENT_SEND_ENVELOPE_DONE, request);
394 uiccCard.sendEnvelopeWithStatus((String)request.argument, onCompleted);
395 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800396 break;
397
398 case EVENT_SEND_ENVELOPE_DONE:
399 ar = (AsyncResult) msg.obj;
400 request = (MainThreadRequest) ar.userObj;
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700401 if (ar.exception == null && ar.result != null) {
402 request.result = ar.result;
Derek Tan4d5e5c12014-02-04 11:54:58 -0800403 } else {
Shishir Agrawal9f9877d2014-03-14 09:36:27 -0700404 request.result = new IccIoResult(0x6F, 0, (byte[])null);
405 if (ar.result == null) {
406 loge("sendEnvelopeWithStatus: Empty response");
407 } else if (ar.exception instanceof CommandException) {
408 loge("sendEnvelopeWithStatus: CommandException: " +
409 ar.exception);
410 } else {
411 loge("sendEnvelopeWithStatus: exception:" + ar.exception);
412 }
Derek Tan4d5e5c12014-02-04 11:54:58 -0800413 }
414 synchronized (request) {
415 request.notifyAll();
416 }
417 break;
418
Shishir Agrawal566b7612013-10-28 14:41:00 -0700419 case CMD_OPEN_CHANNEL:
420 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700421 if (uiccCard == null) {
422 loge("iccOpenLogicalChannel: No UICC");
423 request.result = new IccIoResult(0x6F, 0, (byte[])null);
424 synchronized (request) {
425 request.notifyAll();
426 }
427 } else {
428 onCompleted = obtainMessage(EVENT_OPEN_CHANNEL_DONE, request);
429 uiccCard.iccOpenLogicalChannel((String)request.argument, onCompleted);
430 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700431 break;
432
433 case EVENT_OPEN_CHANNEL_DONE:
434 ar = (AsyncResult) msg.obj;
435 request = (MainThreadRequest) ar.userObj;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700436 IccOpenLogicalChannelResponse openChannelResp;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700437 if (ar.exception == null && ar.result != null) {
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700438 int[] result = (int[]) ar.result;
439 int channelId = result[0];
440 byte[] selectResponse = null;
441 if (result.length > 1) {
442 selectResponse = new byte[result.length - 1];
443 for (int i = 1; i < result.length; ++i) {
444 selectResponse[i - 1] = (byte) result[i];
445 }
446 }
447 openChannelResp = new IccOpenLogicalChannelResponse(channelId,
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700448 IccOpenLogicalChannelResponse.STATUS_NO_ERROR, selectResponse);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700449 } else {
Shishir Agrawal566b7612013-10-28 14:41:00 -0700450 if (ar.result == null) {
451 loge("iccOpenLogicalChannel: Empty response");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700452 }
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700453 if (ar.exception != null) {
454 loge("iccOpenLogicalChannel: Exception: " + ar.exception);
455 }
456
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700457 int errorCode = IccOpenLogicalChannelResponse.STATUS_UNKNOWN_ERROR;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700458 if ((ar.exception != null) && (ar.exception instanceof CommandException)) {
459 if (ar.exception.getMessage().compareTo("MISSING_RESOURCE") == 0) {
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700460 errorCode = IccOpenLogicalChannelResponse.STATUS_MISSING_RESOURCE;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700461 } else if (ar.exception.getMessage().compareTo("NO_SUCH_ELEMENT") == 0) {
Shishir Agrawal527e8bf2014-08-25 08:54:56 -0700462 errorCode = IccOpenLogicalChannelResponse.STATUS_NO_SUCH_ELEMENT;
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -0700463 }
464 }
465 openChannelResp = new IccOpenLogicalChannelResponse(
466 IccOpenLogicalChannelResponse.INVALID_CHANNEL, errorCode, null);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700467 }
Shishir Agrawal82c8a462014-07-31 18:13:17 -0700468 request.result = openChannelResp;
Shishir Agrawal566b7612013-10-28 14:41:00 -0700469 synchronized (request) {
470 request.notifyAll();
471 }
472 break;
473
474 case CMD_CLOSE_CHANNEL:
475 request = (MainThreadRequest) msg.obj;
Shishir Agrawaleb8771e2014-07-22 11:24:08 -0700476 if (uiccCard == null) {
477 loge("iccCloseLogicalChannel: No UICC");
478 request.result = new IccIoResult(0x6F, 0, (byte[])null);
479 synchronized (request) {
480 request.notifyAll();
481 }
482 } else {
483 onCompleted = obtainMessage(EVENT_CLOSE_CHANNEL_DONE, request);
484 uiccCard.iccCloseLogicalChannel((Integer) request.argument, onCompleted);
485 }
Shishir Agrawal566b7612013-10-28 14:41:00 -0700486 break;
487
488 case EVENT_CLOSE_CHANNEL_DONE:
Jake Hambye994d462014-02-03 13:10:13 -0800489 handleNullReturnEvent(msg, "iccCloseLogicalChannel");
490 break;
491
492 case CMD_NV_READ_ITEM:
493 request = (MainThreadRequest) msg.obj;
494 onCompleted = obtainMessage(EVENT_NV_READ_ITEM_DONE, request);
495 mPhone.nvReadItem((Integer) request.argument, onCompleted);
496 break;
497
498 case EVENT_NV_READ_ITEM_DONE:
Shishir Agrawal566b7612013-10-28 14:41:00 -0700499 ar = (AsyncResult) msg.obj;
500 request = (MainThreadRequest) ar.userObj;
Jake Hambye994d462014-02-03 13:10:13 -0800501 if (ar.exception == null && ar.result != null) {
502 request.result = ar.result; // String
Shishir Agrawal566b7612013-10-28 14:41:00 -0700503 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800504 request.result = "";
505 if (ar.result == null) {
506 loge("nvReadItem: Empty response");
507 } else if (ar.exception instanceof CommandException) {
508 loge("nvReadItem: CommandException: " +
509 ar.exception);
Shishir Agrawal566b7612013-10-28 14:41:00 -0700510 } else {
Jake Hambye994d462014-02-03 13:10:13 -0800511 loge("nvReadItem: Unknown exception");
Shishir Agrawal566b7612013-10-28 14:41:00 -0700512 }
513 }
514 synchronized (request) {
515 request.notifyAll();
516 }
517 break;
518
Jake Hambye994d462014-02-03 13:10:13 -0800519 case CMD_NV_WRITE_ITEM:
520 request = (MainThreadRequest) msg.obj;
521 onCompleted = obtainMessage(EVENT_NV_WRITE_ITEM_DONE, request);
522 Pair<Integer, String> idValue = (Pair<Integer, String>) request.argument;
523 mPhone.nvWriteItem(idValue.first, idValue.second, onCompleted);
524 break;
525
526 case EVENT_NV_WRITE_ITEM_DONE:
527 handleNullReturnEvent(msg, "nvWriteItem");
528 break;
529
530 case CMD_NV_WRITE_CDMA_PRL:
531 request = (MainThreadRequest) msg.obj;
532 onCompleted = obtainMessage(EVENT_NV_WRITE_CDMA_PRL_DONE, request);
533 mPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
534 break;
535
536 case EVENT_NV_WRITE_CDMA_PRL_DONE:
537 handleNullReturnEvent(msg, "nvWriteCdmaPrl");
538 break;
539
540 case CMD_NV_RESET_CONFIG:
541 request = (MainThreadRequest) msg.obj;
542 onCompleted = obtainMessage(EVENT_NV_RESET_CONFIG_DONE, request);
543 mPhone.nvResetConfig((Integer) request.argument, onCompleted);
544 break;
545
546 case EVENT_NV_RESET_CONFIG_DONE:
547 handleNullReturnEvent(msg, "nvResetConfig");
548 break;
549
Jake Hamby7c27be32014-03-03 13:25:59 -0800550 case CMD_GET_PREFERRED_NETWORK_TYPE:
551 request = (MainThreadRequest) msg.obj;
552 onCompleted = obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE_DONE, request);
553 mPhone.getPreferredNetworkType(onCompleted);
554 break;
555
556 case EVENT_GET_PREFERRED_NETWORK_TYPE_DONE:
557 ar = (AsyncResult) msg.obj;
558 request = (MainThreadRequest) ar.userObj;
559 if (ar.exception == null && ar.result != null) {
560 request.result = ar.result; // Integer
561 } else {
562 request.result = -1;
563 if (ar.result == null) {
564 loge("getPreferredNetworkType: Empty response");
565 } else if (ar.exception instanceof CommandException) {
566 loge("getPreferredNetworkType: CommandException: " +
567 ar.exception);
568 } else {
569 loge("getPreferredNetworkType: Unknown exception");
570 }
571 }
572 synchronized (request) {
573 request.notifyAll();
574 }
575 break;
576
577 case CMD_SET_PREFERRED_NETWORK_TYPE:
578 request = (MainThreadRequest) msg.obj;
579 onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);
580 int networkType = (Integer) request.argument;
581 mPhone.setPreferredNetworkType(networkType, onCompleted);
582 break;
583
584 case EVENT_SET_PREFERRED_NETWORK_TYPE_DONE:
585 handleNullReturnEvent(msg, "setPreferredNetworkType");
586 break;
587
Steven Liu4bf01bc2014-07-17 11:05:29 -0500588 case CMD_INVOKE_OEM_RIL_REQUEST_RAW:
589 request = (MainThreadRequest)msg.obj;
590 onCompleted = obtainMessage(EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE, request);
591 mPhone.invokeOemRilRequestRaw((byte[])request.argument, onCompleted);
592 break;
593
594 case EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE:
595 ar = (AsyncResult)msg.obj;
596 request = (MainThreadRequest)ar.userObj;
597 request.result = ar;
598 synchronized (request) {
599 request.notifyAll();
600 }
601 break;
602
Shishir Agrawal76d5da92014-11-09 16:17:25 -0800603 case CMD_SET_VOICEMAIL_NUMBER:
604 request = (MainThreadRequest) msg.obj;
605 onCompleted = obtainMessage(EVENT_SET_VOICEMAIL_NUMBER_DONE, request);
606 Pair<String, String> tagNum = (Pair<String, String>) request.argument;
607 Phone phone = (request.subId == null) ? mPhone : getPhone(request.subId);
608 phone.setVoiceMailNumber(tagNum.first, tagNum.second, onCompleted);
609 break;
610
611 case EVENT_SET_VOICEMAIL_NUMBER_DONE:
612 handleNullReturnEvent(msg, "setVoicemailNumber");
613 break;
614
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700615 default:
616 Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
617 break;
618 }
619 }
Jake Hambye994d462014-02-03 13:10:13 -0800620
621 private void handleNullReturnEvent(Message msg, String command) {
622 AsyncResult ar = (AsyncResult) msg.obj;
623 MainThreadRequest request = (MainThreadRequest) ar.userObj;
624 if (ar.exception == null) {
625 request.result = true;
626 } else {
627 request.result = false;
628 if (ar.exception instanceof CommandException) {
629 loge(command + ": CommandException: " + ar.exception);
630 } else {
631 loge(command + ": Unknown exception");
632 }
633 }
634 synchronized (request) {
635 request.notifyAll();
636 }
637 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700638 }
639
640 /**
641 * Posts the specified command to be executed on the main thread,
642 * waits for the request to complete, and returns the result.
643 * @see #sendRequestAsync
644 */
645 private Object sendRequest(int command, Object argument) {
Santos Cordon500b0e02014-06-17 10:33:33 -0700646 return sendRequest(command, argument, null);
Wink Saville36469e72014-06-11 15:17:00 -0700647 }
648
649 /**
650 * Posts the specified command to be executed on the main thread,
651 * waits for the request to complete, and returns the result.
652 * @see #sendRequestAsync
653 */
Shishir Agrawal76d5da92014-11-09 16:17:25 -0800654 private Object sendRequest(int command, Object argument, Integer subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700655 if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
656 throw new RuntimeException("This method will deadlock if called from the main thread.");
657 }
658
Shishir Agrawal76d5da92014-11-09 16:17:25 -0800659 MainThreadRequest request = new MainThreadRequest(argument, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700660 Message msg = mMainThreadHandler.obtainMessage(command, request);
661 msg.sendToTarget();
662
663 // Wait for the request to complete
664 synchronized (request) {
665 while (request.result == null) {
666 try {
667 request.wait();
668 } catch (InterruptedException e) {
669 // Do nothing, go back and wait until the request is complete
670 }
671 }
672 }
673 return request.result;
674 }
675
676 /**
677 * Asynchronous ("fire and forget") version of sendRequest():
678 * Posts the specified command to be executed on the main thread, and
679 * returns immediately.
680 * @see #sendRequest
681 */
682 private void sendRequestAsync(int command) {
683 mMainThreadHandler.sendEmptyMessage(command);
684 }
685
686 /**
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -0700687 * Same as {@link #sendRequestAsync(int)} except it takes an argument.
688 * @see {@link #sendRequest(int,Object)}
689 */
690 private void sendRequestAsync(int command, Object argument) {
691 MainThreadRequest request = new MainThreadRequest(argument);
692 Message msg = mMainThreadHandler.obtainMessage(command, request);
693 msg.sendToTarget();
694 }
695
696 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700697 * Initialize the singleton PhoneInterfaceManager instance.
698 * This is only done once, at startup, from PhoneApp.onCreate().
699 */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700700 /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700701 synchronized (PhoneInterfaceManager.class) {
702 if (sInstance == null) {
Sailesh Nepal194161e2014-07-03 08:57:44 -0700703 sInstance = new PhoneInterfaceManager(app, phone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700704 } else {
705 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
706 }
707 return sInstance;
708 }
709 }
710
711 /** Private constructor; @see init() */
Sailesh Nepal194161e2014-07-03 08:57:44 -0700712 private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700713 mApp = app;
714 mPhone = phone;
715 mCM = PhoneGlobals.getInstance().mCM;
716 mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
717 mMainThreadHandler = new MainThreadHandler();
Andrew Leedf14ead2014-10-17 14:22:52 -0700718 mTelephonySharedPreferences =
Derek Tan97ebb422014-09-05 16:55:38 -0700719 PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
Wink Savilleac1bdfd2014-11-20 23:04:44 -0800720 mSubscriptionController = SubscriptionController.getInstance();
Wink Saville3ab207e2014-11-20 13:07:20 -0800721
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700722 publish();
723 }
724
725 private void publish() {
726 if (DBG) log("publish: " + this);
727
728 ServiceManager.addService("phone", this);
729 }
730
Wink Saville36469e72014-06-11 15:17:00 -0700731 // returns phone associated with the subId.
Wink Savilleb564aae2014-10-23 10:18:09 -0700732 private Phone getPhone(int subId) {
Wink Savilleac1bdfd2014-11-20 23:04:44 -0800733 return PhoneFactory.getPhone(mSubscriptionController.getPhoneId(subId));
Wink Saville36469e72014-06-11 15:17:00 -0700734 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700735 //
736 // Implementation of the ITelephony interface.
737 //
738
739 public void dial(String number) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700740 dialForSubscriber(getPreferredVoiceSubscription(), number);
Wink Saville36469e72014-06-11 15:17:00 -0700741 }
742
Wink Savilleb564aae2014-10-23 10:18:09 -0700743 public void dialForSubscriber(int subId, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700744 if (DBG) log("dial: " + number);
745 // No permission check needed here: This is just a wrapper around the
746 // ACTION_DIAL intent, which is available to any app since it puts up
747 // the UI before it does anything.
748
749 String url = createTelUrl(number);
750 if (url == null) {
751 return;
752 }
753
754 // PENDING: should we just silently fail if phone is offhook or ringing?
Wink Saville36469e72014-06-11 15:17:00 -0700755 PhoneConstants.State state = mCM.getState(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700756 if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
757 Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
758 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
759 mApp.startActivity(intent);
760 }
761 }
762
763 public void call(String callingPackage, String number) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700764 callForSubscriber(getPreferredVoiceSubscription(), callingPackage, number);
Wink Saville36469e72014-06-11 15:17:00 -0700765 }
766
Wink Savilleb564aae2014-10-23 10:18:09 -0700767 public void callForSubscriber(int subId, String callingPackage, String number) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700768 if (DBG) log("call: " + number);
769
770 // This is just a wrapper around the ACTION_CALL intent, but we still
771 // need to do a permission check since we're calling startActivity()
772 // from the context of the phone app.
773 enforceCallPermission();
774
775 if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
776 != AppOpsManager.MODE_ALLOWED) {
777 return;
778 }
779
780 String url = createTelUrl(number);
781 if (url == null) {
782 return;
783 }
784
Wink Saville08874612014-08-31 19:19:58 -0700785 boolean isValid = false;
Wink Savilleac1bdfd2014-11-20 23:04:44 -0800786 List<SubscriptionInfo> slist = mSubscriptionController.getActiveSubscriptionInfoList();
Wink Saville3ab207e2014-11-20 13:07:20 -0800787 if (slist != null) {
788 for (SubscriptionInfo subInfoRecord : slist) {
789 if (subInfoRecord.getSubscriptionId() == subId) {
790 isValid = true;
791 break;
792 }
Wink Saville08874612014-08-31 19:19:58 -0700793 }
794 }
795 if (isValid == false) {
796 return;
797 }
798
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700799 Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
Wink Saville36469e72014-06-11 15:17:00 -0700800 intent.putExtra(SUBSCRIPTION_KEY, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700801 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
802 mApp.startActivity(intent);
803 }
804
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700805 /**
806 * End a call based on call state
807 * @return true is a call was ended
808 */
809 public boolean endCall() {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700810 return endCallForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -0700811 }
812
813 /**
814 * End a call based on the call state of the subId
815 * @return true is a call was ended
816 */
Wink Savilleb564aae2014-10-23 10:18:09 -0700817 public boolean endCallForSubscriber(int subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700818 enforceCallPermission();
Wink Saville9f73bda2014-11-05 08:13:36 -0800819 return (Boolean) sendRequest(CMD_END_CALL, new Integer(subId), null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700820 }
821
822 public void answerRingingCall() {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700823 answerRingingCallForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -0700824 }
825
Wink Savilleb564aae2014-10-23 10:18:09 -0700826 public void answerRingingCallForSubscriber(int subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700827 if (DBG) log("answerRingingCall...");
828 // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
829 // but that can probably wait till the big TelephonyManager API overhaul.
830 // For now, protect this call with the MODIFY_PHONE_STATE permission.
831 enforceModifyPermission();
Wink Saville9f73bda2014-11-05 08:13:36 -0800832 sendRequest(CMD_ANSWER_RINGING_CALL, new Integer(subId), null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700833 }
834
835 /**
836 * Make the actual telephony calls to implement answerRingingCall().
837 * This should only be called from the main thread of the Phone app.
838 * @see #answerRingingCall
839 *
840 * TODO: it would be nice to return true if we answered the call, or
841 * false if there wasn't actually a ringing incoming call, or some
842 * other error occurred. (In other words, pass back the return value
843 * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
844 * But that would require calling this method via sendRequest() rather
845 * than sendRequestAsync(), and right now we don't actually *need* that
846 * return value, so let's just return void for now.
847 */
Wink Savilleb564aae2014-10-23 10:18:09 -0700848 private void answerRingingCallInternal(int subId) {
Wink Saville08874612014-08-31 19:19:58 -0700849 final boolean hasRingingCall = !getPhone(subId).getRingingCall().isIdle();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700850 if (hasRingingCall) {
Wink Saville08874612014-08-31 19:19:58 -0700851 final boolean hasActiveCall = !getPhone(subId).getForegroundCall().isIdle();
852 final boolean hasHoldingCall = !getPhone(subId).getBackgroundCall().isIdle();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700853 if (hasActiveCall && hasHoldingCall) {
854 // Both lines are in use!
855 // TODO: provide a flag to let the caller specify what
856 // policy to use if both lines are in use. (The current
857 // behavior is hardwired to "answer incoming, end ongoing",
858 // which is how the CALL button is specced to behave.)
859 PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
860 return;
861 } else {
862 // answerCall() will automatically hold the current active
863 // call, if there is one.
864 PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
865 return;
866 }
867 } else {
868 // No call was ringing.
869 return;
870 }
871 }
872
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700873 /**
Santos Cordon5422a8d2014-09-12 04:20:56 -0700874 * This method is no longer used and can be removed once TelephonyManager stops referring to it.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700875 */
Santos Cordon5422a8d2014-09-12 04:20:56 -0700876 public void silenceRinger() {
877 Log.e(LOG_TAG, "silenseRinger not supported");
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700878 }
879
880 public boolean isOffhook() {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700881 return isOffhookForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -0700882 }
883
Wink Savilleb564aae2014-10-23 10:18:09 -0700884 public boolean isOffhookForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -0700885 return (getPhone(subId).getState() == PhoneConstants.State.OFFHOOK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700886 }
887
888 public boolean isRinging() {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700889 return (isRingingForSubscriber(getDefaultSubscription()));
Wink Saville36469e72014-06-11 15:17:00 -0700890 }
891
Wink Savilleb564aae2014-10-23 10:18:09 -0700892 public boolean isRingingForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -0700893 return (getPhone(subId).getState() == PhoneConstants.State.RINGING);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700894 }
895
896 public boolean isIdle() {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700897 return isIdleForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -0700898 }
899
Wink Savilleb564aae2014-10-23 10:18:09 -0700900 public boolean isIdleForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -0700901 return (getPhone(subId).getState() == PhoneConstants.State.IDLE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700902 }
903
904 public boolean isSimPinEnabled() {
905 enforceReadPermission();
906 return (PhoneGlobals.getInstance().isSimPinEnabled());
907 }
908
909 public boolean supplyPin(String pin) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700910 return supplyPinForSubscriber(getDefaultSubscription(), pin);
Wink Saville36469e72014-06-11 15:17:00 -0700911 }
912
Wink Savilleb564aae2014-10-23 10:18:09 -0700913 public boolean supplyPinForSubscriber(int subId, String pin) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700914 int [] resultArray = supplyPinReportResultForSubscriber(subId, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700915 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
916 }
917
918 public boolean supplyPuk(String puk, String pin) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700919 return supplyPukForSubscriber(getDefaultSubscription(), puk, pin);
Wink Saville36469e72014-06-11 15:17:00 -0700920 }
921
Wink Savilleb564aae2014-10-23 10:18:09 -0700922 public boolean supplyPukForSubscriber(int subId, String puk, String pin) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700923 int [] resultArray = supplyPukReportResultForSubscriber(subId, puk, pin);
Wink Saville9de0f752013-10-22 19:04:03 -0700924 return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
925 }
926
927 /** {@hide} */
928 public int[] supplyPinReportResult(String pin) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700929 return supplyPinReportResultForSubscriber(getDefaultSubscription(), pin);
Wink Saville36469e72014-06-11 15:17:00 -0700930 }
931
Wink Savilleb564aae2014-10-23 10:18:09 -0700932 public int[] supplyPinReportResultForSubscriber(int subId, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700933 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700934 final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700935 checkSimPin.start();
936 return checkSimPin.unlockSim(null, pin);
937 }
938
Wink Saville9de0f752013-10-22 19:04:03 -0700939 /** {@hide} */
940 public int[] supplyPukReportResult(String puk, String pin) {
Wink Savilleadd7cc52014-09-08 14:23:09 -0700941 return supplyPukReportResultForSubscriber(getDefaultSubscription(), puk, pin);
Wink Saville36469e72014-06-11 15:17:00 -0700942 }
943
Wink Savilleb564aae2014-10-23 10:18:09 -0700944 public int[] supplyPukReportResultForSubscriber(int subId, String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700945 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -0700946 final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700947 checkSimPuk.start();
948 return checkSimPuk.unlockSim(puk, pin);
949 }
950
951 /**
Wink Saville9de0f752013-10-22 19:04:03 -0700952 * Helper thread to turn async call to SimCard#supplyPin into
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700953 * a synchronous one.
954 */
955 private static class UnlockSim extends Thread {
956
957 private final IccCard mSimCard;
958
959 private boolean mDone = false;
Wink Saville9de0f752013-10-22 19:04:03 -0700960 private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
961 private int mRetryCount = -1;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700962
963 // For replies from SimCard interface
964 private Handler mHandler;
965
966 // For async handler to identify request type
967 private static final int SUPPLY_PIN_COMPLETE = 100;
968
969 public UnlockSim(IccCard simCard) {
970 mSimCard = simCard;
971 }
972
973 @Override
974 public void run() {
975 Looper.prepare();
976 synchronized (UnlockSim.this) {
977 mHandler = new Handler() {
978 @Override
979 public void handleMessage(Message msg) {
980 AsyncResult ar = (AsyncResult) msg.obj;
981 switch (msg.what) {
982 case SUPPLY_PIN_COMPLETE:
983 Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
984 synchronized (UnlockSim.this) {
Wink Saville9de0f752013-10-22 19:04:03 -0700985 mRetryCount = msg.arg1;
986 if (ar.exception != null) {
987 if (ar.exception instanceof CommandException &&
988 ((CommandException)(ar.exception)).getCommandError()
989 == CommandException.Error.PASSWORD_INCORRECT) {
990 mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
991 } else {
992 mResult = PhoneConstants.PIN_GENERAL_FAILURE;
993 }
994 } else {
995 mResult = PhoneConstants.PIN_RESULT_SUCCESS;
996 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700997 mDone = true;
998 UnlockSim.this.notifyAll();
999 }
1000 break;
1001 }
1002 }
1003 };
1004 UnlockSim.this.notifyAll();
1005 }
1006 Looper.loop();
1007 }
1008
1009 /*
1010 * Use PIN or PUK to unlock SIM card
1011 *
1012 * If PUK is null, unlock SIM card with PIN
1013 *
1014 * If PUK is not null, unlock SIM card with PUK and set PIN code
1015 */
Wink Saville9de0f752013-10-22 19:04:03 -07001016 synchronized int[] unlockSim(String puk, String pin) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001017
1018 while (mHandler == null) {
1019 try {
1020 wait();
1021 } catch (InterruptedException e) {
1022 Thread.currentThread().interrupt();
1023 }
1024 }
1025 Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
1026
1027 if (puk == null) {
1028 mSimCard.supplyPin(pin, callback);
1029 } else {
1030 mSimCard.supplyPuk(puk, pin, callback);
1031 }
1032
1033 while (!mDone) {
1034 try {
1035 Log.d(LOG_TAG, "wait for done");
1036 wait();
1037 } catch (InterruptedException e) {
1038 // Restore the interrupted status
1039 Thread.currentThread().interrupt();
1040 }
1041 }
1042 Log.d(LOG_TAG, "done");
Wink Saville9de0f752013-10-22 19:04:03 -07001043 int[] resultArray = new int[2];
1044 resultArray[0] = mResult;
1045 resultArray[1] = mRetryCount;
1046 return resultArray;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001047 }
1048 }
1049
1050 public void updateServiceLocation() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001051 updateServiceLocationForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001052
1053 }
1054
Wink Savilleb564aae2014-10-23 10:18:09 -07001055 public void updateServiceLocationForSubscriber(int subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001056 // No permission check needed here: this call is harmless, and it's
1057 // needed for the ServiceState.requestStateUpdate() call (which is
1058 // already intentionally exposed to 3rd parties.)
Wink Saville36469e72014-06-11 15:17:00 -07001059 getPhone(subId).updateServiceLocation();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001060 }
1061
1062 public boolean isRadioOn() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001063 return isRadioOnForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001064 }
1065
Wink Savilleb564aae2014-10-23 10:18:09 -07001066 public boolean isRadioOnForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001067 return getPhone(subId).getServiceState().getState() != ServiceState.STATE_POWER_OFF;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001068 }
1069
1070 public void toggleRadioOnOff() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001071 toggleRadioOnOffForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001072
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001073 }
Wink Saville36469e72014-06-11 15:17:00 -07001074
Wink Savilleb564aae2014-10-23 10:18:09 -07001075 public void toggleRadioOnOffForSubscriber(int subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001076 enforceModifyPermission();
Wink Savilleadd7cc52014-09-08 14:23:09 -07001077 getPhone(subId).setRadioPower(!isRadioOnForSubscriber(subId));
Wink Saville36469e72014-06-11 15:17:00 -07001078 }
1079
1080 public boolean setRadio(boolean turnOn) {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001081 return setRadioForSubscriber(getDefaultSubscription(), turnOn);
Wink Saville36469e72014-06-11 15:17:00 -07001082 }
1083
Wink Savilleb564aae2014-10-23 10:18:09 -07001084 public boolean setRadioForSubscriber(int subId, boolean turnOn) {
Wink Saville36469e72014-06-11 15:17:00 -07001085 enforceModifyPermission();
1086 if ((getPhone(subId).getServiceState().getState() !=
1087 ServiceState.STATE_POWER_OFF) != turnOn) {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001088 toggleRadioOnOffForSubscriber(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001089 }
1090 return true;
1091 }
Wink Saville36469e72014-06-11 15:17:00 -07001092
Naveen Kalla1fd79bd2014-08-08 00:48:59 -07001093 public boolean needMobileRadioShutdown() {
1094 /*
1095 * If any of the Radios are available, it will need to be
1096 * shutdown. So return true if any Radio is available.
1097 */
1098 for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
1099 Phone phone = PhoneFactory.getPhone(i);
1100 if (phone != null && phone.isRadioAvailable()) return true;
1101 }
1102 logv(TelephonyManager.getDefault().getPhoneCount() + " Phones are shutdown.");
1103 return false;
1104 }
1105
1106 public void shutdownMobileRadios() {
1107 for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
1108 logv("Shutting down Phone " + i);
1109 shutdownRadioUsingPhoneId(i);
1110 }
1111 }
1112
1113 private void shutdownRadioUsingPhoneId(int phoneId) {
1114 enforceModifyPermission();
1115 Phone phone = PhoneFactory.getPhone(phoneId);
1116 if (phone != null && phone.isRadioAvailable()) {
1117 phone.shutdownRadio();
1118 }
1119 }
1120
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001121 public boolean setRadioPower(boolean turnOn) {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001122 return setRadioPowerForSubscriber(getDefaultSubscription(), turnOn);
Wink Saville36469e72014-06-11 15:17:00 -07001123 }
1124
Wink Savilleb564aae2014-10-23 10:18:09 -07001125 public boolean setRadioPowerForSubscriber(int subId, boolean turnOn) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001126 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001127 getPhone(subId).setRadioPower(turnOn);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001128 return true;
1129 }
1130
Wink Saville36469e72014-06-11 15:17:00 -07001131 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001132 public boolean enableDataConnectivity() {
1133 enforceModifyPermission();
Wink Savilleac1bdfd2014-11-20 23:04:44 -08001134 int subId = mSubscriptionController.getDefaultDataSubId();
Wink Saville36469e72014-06-11 15:17:00 -07001135 getPhone(subId).setDataEnabled(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001136 return true;
1137 }
1138
Wink Saville36469e72014-06-11 15:17:00 -07001139 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001140 public boolean disableDataConnectivity() {
1141 enforceModifyPermission();
Wink Savilleac1bdfd2014-11-20 23:04:44 -08001142 int subId = mSubscriptionController.getDefaultDataSubId();
Wink Saville36469e72014-06-11 15:17:00 -07001143 getPhone(subId).setDataEnabled(false);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001144 return true;
1145 }
1146
Wink Saville36469e72014-06-11 15:17:00 -07001147 // FIXME: subId version needed
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001148 public boolean isDataConnectivityPossible() {
Wink Savilleac1bdfd2014-11-20 23:04:44 -08001149 int subId = mSubscriptionController.getDefaultDataSubId();
Wink Saville36469e72014-06-11 15:17:00 -07001150 return getPhone(subId).isDataConnectivityPossible();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001151 }
1152
1153 public boolean handlePinMmi(String dialString) {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001154 return handlePinMmiForSubscriber(getDefaultSubscription(), dialString);
Wink Saville36469e72014-06-11 15:17:00 -07001155 }
1156
Wink Savilleb564aae2014-10-23 10:18:09 -07001157 public boolean handlePinMmiForSubscriber(int subId, String dialString) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001158 enforceModifyPermission();
Wink Saville36469e72014-06-11 15:17:00 -07001159 return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001160 }
1161
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001162 public int getCallState() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001163 return getCallStateForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001164 }
1165
Wink Savilleb564aae2014-10-23 10:18:09 -07001166 public int getCallStateForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001167 return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001168 }
1169
1170 public int getDataState() {
Wink Savilleac1bdfd2014-11-20 23:04:44 -08001171 Phone phone = getPhone(mSubscriptionController.getDefaultDataSubId());
Wink Saville36469e72014-06-11 15:17:00 -07001172 return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001173 }
1174
1175 public int getDataActivity() {
Wink Savilleac1bdfd2014-11-20 23:04:44 -08001176 Phone phone = getPhone(mSubscriptionController.getDefaultDataSubId());
Wink Saville36469e72014-06-11 15:17:00 -07001177 return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001178 }
1179
1180 @Override
1181 public Bundle getCellLocation() {
1182 try {
1183 mApp.enforceCallingOrSelfPermission(
1184 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1185 } catch (SecurityException e) {
1186 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1187 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1188 // is the weaker precondition
1189 mApp.enforceCallingOrSelfPermission(
1190 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1191 }
1192
Jake Hambye994d462014-02-03 13:10:13 -08001193 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001194 if (DBG_LOC) log("getCellLocation: is active user");
1195 Bundle data = new Bundle();
Legler Wu2c01cdf2014-12-08 19:00:59 +08001196 Phone phone = getPhone(mSubscriptionController.getDefaultDataSubId());
1197 phone.getCellLocation().fillInNotifierBundle(data);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001198 return data;
1199 } else {
1200 if (DBG_LOC) log("getCellLocation: suppress non-active user");
1201 return null;
1202 }
1203 }
1204
1205 @Override
1206 public void enableLocationUpdates() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001207 enableLocationUpdatesForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001208 }
1209
Wink Savilleb564aae2014-10-23 10:18:09 -07001210 public void enableLocationUpdatesForSubscriber(int subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001211 mApp.enforceCallingOrSelfPermission(
1212 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001213 getPhone(subId).enableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001214 }
1215
1216 @Override
1217 public void disableLocationUpdates() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001218 disableLocationUpdatesForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001219 }
1220
Wink Savilleb564aae2014-10-23 10:18:09 -07001221 public void disableLocationUpdatesForSubscriber(int subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001222 mApp.enforceCallingOrSelfPermission(
1223 android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
Wink Saville36469e72014-06-11 15:17:00 -07001224 getPhone(subId).disableLocationUpdates();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001225 }
1226
1227 @Override
1228 @SuppressWarnings("unchecked")
1229 public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1230 try {
1231 mApp.enforceCallingOrSelfPermission(
1232 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1233 } catch (SecurityException e) {
1234 // If we have ACCESS_FINE_LOCATION permission, skip the check
1235 // for ACCESS_COARSE_LOCATION
1236 // A failure should throw the SecurityException from
1237 // ACCESS_COARSE_LOCATION since this is the weaker precondition
1238 mApp.enforceCallingOrSelfPermission(
1239 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1240 }
1241
1242 if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1243 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1244 return null;
1245 }
Jake Hambye994d462014-02-03 13:10:13 -08001246 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001247 if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1248
1249 ArrayList<NeighboringCellInfo> cells = null;
1250
1251 try {
1252 cells = (ArrayList<NeighboringCellInfo>) sendRequest(
Wink Saville36469e72014-06-11 15:17:00 -07001253 CMD_HANDLE_NEIGHBORING_CELL, null, null);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001254 } catch (RuntimeException e) {
Wink Saville36469e72014-06-11 15:17:00 -07001255 Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001256 }
1257 return cells;
1258 } else {
1259 if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1260 return null;
1261 }
1262 }
1263
1264
1265 @Override
1266 public List<CellInfo> getAllCellInfo() {
1267 try {
1268 mApp.enforceCallingOrSelfPermission(
1269 android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1270 } catch (SecurityException e) {
1271 // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1272 // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1273 // is the weaker precondition
1274 mApp.enforceCallingOrSelfPermission(
1275 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1276 }
1277
Jake Hambye994d462014-02-03 13:10:13 -08001278 if (checkIfCallerIsSelfOrForegroundUser()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001279 if (DBG_LOC) log("getAllCellInfo: is active user");
Legler Wu2c01cdf2014-12-08 19:00:59 +08001280 List<CellInfo> cellInfos = new ArrayList<CellInfo>();
1281 for (Phone phone : PhoneFactory.getPhones()) {
1282 cellInfos.addAll(phone.getAllCellInfo());
1283 }
1284 return cellInfos;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001285 } else {
1286 if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1287 return null;
1288 }
1289 }
1290
Sailesh Nepalbd76e4e2013-10-27 13:59:44 -07001291 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001292 public void setCellInfoListRate(int rateInMillis) {
1293 mPhone.setCellInfoListRate(rateInMillis);
1294 }
1295
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001296 //
1297 // Internal helper methods.
1298 //
1299
Jake Hambye994d462014-02-03 13:10:13 -08001300 private static boolean checkIfCallerIsSelfOrForegroundUser() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001301 boolean ok;
1302
1303 boolean self = Binder.getCallingUid() == Process.myUid();
1304 if (!self) {
1305 // Get the caller's user id then clear the calling identity
1306 // which will be restored in the finally clause.
1307 int callingUser = UserHandle.getCallingUserId();
1308 long ident = Binder.clearCallingIdentity();
1309
1310 try {
1311 // With calling identity cleared the current user is the foreground user.
1312 int foregroundUser = ActivityManager.getCurrentUser();
1313 ok = (foregroundUser == callingUser);
1314 if (DBG_LOC) {
1315 log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1316 + " callingUser=" + callingUser + " ok=" + ok);
1317 }
1318 } catch (Exception ex) {
1319 if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1320 ok = false;
1321 } finally {
1322 Binder.restoreCallingIdentity(ident);
1323 }
1324 } else {
1325 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1326 ok = true;
1327 }
1328 if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1329 return ok;
1330 }
1331
1332 /**
1333 * Make sure the caller has the READ_PHONE_STATE permission.
1334 *
1335 * @throws SecurityException if the caller does not have the required permission
1336 */
1337 private void enforceReadPermission() {
1338 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
1339 }
1340
1341 /**
1342 * Make sure the caller has the MODIFY_PHONE_STATE permission.
1343 *
1344 * @throws SecurityException if the caller does not have the required permission
1345 */
1346 private void enforceModifyPermission() {
1347 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1348 }
1349
1350 /**
Junda Liua2e36012014-07-09 18:30:01 -07001351 * Make sure either system app or the caller has carrier privilege.
1352 *
1353 * @throws SecurityException if the caller does not have the required permission/privilege
1354 */
1355 private void enforceModifyPermissionOrCarrierPrivilege() {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001356 int permission = mApp.checkCallingOrSelfPermission(
1357 android.Manifest.permission.MODIFY_PHONE_STATE);
1358 if (permission == PackageManager.PERMISSION_GRANTED) {
1359 return;
1360 }
1361
1362 log("No modify permission, check carrier privilege next.");
Shishir Agrawal5e5becd2014-11-18 11:38:23 -08001363 if (getCarrierPrivilegeStatus() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001364 loge("No Carrier Privilege.");
1365 throw new SecurityException("No modify permission or carrier privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001366 }
1367 }
1368
1369 /**
1370 * Make sure the caller has carrier privilege.
1371 *
1372 * @throws SecurityException if the caller does not have the required permission
1373 */
1374 private void enforceCarrierPrivilege() {
Shishir Agrawal5e5becd2014-11-18 11:38:23 -08001375 if (getCarrierPrivilegeStatus() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001376 loge("No Carrier Privilege.");
1377 throw new SecurityException("No Carrier Privilege.");
Junda Liua2e36012014-07-09 18:30:01 -07001378 }
1379 }
1380
1381 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001382 * Make sure the caller has the CALL_PHONE permission.
1383 *
1384 * @throws SecurityException if the caller does not have the required permission
1385 */
1386 private void enforceCallPermission() {
1387 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1388 }
1389
Shishir Agrawal566b7612013-10-28 14:41:00 -07001390 /**
Gabriel Peal36ebb0d2014-03-20 09:20:43 -07001391 * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1392 *
1393 * @throws SecurityException if the caller does not have the required permission
1394 */
1395 private void enforcePrivilegedPhoneStatePermission() {
1396 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1397 null);
1398 }
1399
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001400 private String createTelUrl(String number) {
1401 if (TextUtils.isEmpty(number)) {
1402 return null;
1403 }
1404
Jake Hambye994d462014-02-03 13:10:13 -08001405 return "tel:" + number;
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001406 }
1407
Ihab Awadf9e92732013-12-05 18:02:52 -08001408 private static void log(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001409 Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1410 }
1411
Naveen Kalla1fd79bd2014-08-08 00:48:59 -07001412 private static void logv(String msg) {
1413 Log.v(LOG_TAG, "[PhoneIntfMgr] " + msg);
1414 }
1415
Ihab Awadf9e92732013-12-05 18:02:52 -08001416 private static void loge(String msg) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001417 Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1418 }
1419
1420 public int getActivePhoneType() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001421 return getActivePhoneTypeForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001422 }
1423
Wink Savilleb564aae2014-10-23 10:18:09 -07001424 public int getActivePhoneTypeForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001425 return getPhone(subId).getPhoneType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001426 }
1427
1428 /**
1429 * Returns the CDMA ERI icon index to display
1430 */
1431 public int getCdmaEriIconIndex() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001432 return getCdmaEriIconIndexForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001433
1434 }
1435
Wink Savilleb564aae2014-10-23 10:18:09 -07001436 public int getCdmaEriIconIndexForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001437 return getPhone(subId).getCdmaEriIconIndex();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001438 }
1439
1440 /**
1441 * Returns the CDMA ERI icon mode,
1442 * 0 - ON
1443 * 1 - FLASHING
1444 */
1445 public int getCdmaEriIconMode() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001446 return getCdmaEriIconModeForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001447 }
1448
Wink Savilleb564aae2014-10-23 10:18:09 -07001449 public int getCdmaEriIconModeForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001450 return getPhone(subId).getCdmaEriIconMode();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001451 }
1452
1453 /**
1454 * Returns the CDMA ERI text,
1455 */
1456 public String getCdmaEriText() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001457 return getCdmaEriTextForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001458 }
1459
Wink Savilleb564aae2014-10-23 10:18:09 -07001460 public String getCdmaEriTextForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001461 return getPhone(subId).getCdmaEriText();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001462 }
1463
1464 /**
Junda Liuca05d5d2014-08-14 22:36:34 -07001465 * Returns the CDMA MDN.
1466 */
Wink Savilleb564aae2014-10-23 10:18:09 -07001467 public String getCdmaMdn(int subId) {
Junda Liuca05d5d2014-08-14 22:36:34 -07001468 enforceModifyPermissionOrCarrierPrivilege();
1469 if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
1470 return getPhone(subId).getLine1Number();
1471 } else {
1472 return null;
1473 }
1474 }
1475
1476 /**
1477 * Returns the CDMA MIN.
1478 */
Wink Savilleb564aae2014-10-23 10:18:09 -07001479 public String getCdmaMin(int subId) {
Junda Liuca05d5d2014-08-14 22:36:34 -07001480 enforceModifyPermissionOrCarrierPrivilege();
1481 if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
1482 return getPhone(subId).getCdmaMin();
1483 } else {
1484 return null;
1485 }
1486 }
1487
1488 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001489 * Returns true if CDMA provisioning needs to run.
1490 */
1491 public boolean needsOtaServiceProvisioning() {
1492 return mPhone.needsOtaServiceProvisioning();
1493 }
1494
1495 /**
Shishir Agrawal76d5da92014-11-09 16:17:25 -08001496 * Sets the voice mail number of a given subId.
1497 */
1498 @Override
1499 public boolean setVoiceMailNumber(int subId, String alphaTag, String number) {
Shishir Agrawal5e5becd2014-11-18 11:38:23 -08001500 enforceCarrierPrivilege();
Shishir Agrawal76d5da92014-11-09 16:17:25 -08001501 Boolean success = (Boolean) sendRequest(CMD_SET_VOICEMAIL_NUMBER,
1502 new Pair<String, String>(alphaTag, number), new Integer(subId));
1503 return success;
1504 }
1505
1506 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001507 * Returns the unread count of voicemails
1508 */
1509 public int getVoiceMessageCount() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001510 return getVoiceMessageCountForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001511 }
1512
1513 /**
1514 * Returns the unread count of voicemails for a subId
1515 */
Wink Savilleb564aae2014-10-23 10:18:09 -07001516 public int getVoiceMessageCountForSubscriber( int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001517 return getPhone(subId).getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001518 }
1519
1520 /**
1521 * Returns the data network type
1522 *
1523 * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1524 */
1525 @Override
1526 public int getNetworkType() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001527 return getNetworkTypeForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001528 }
1529
1530 /**
1531 * Returns the network type for a subId
1532 */
1533 @Override
Wink Savilleb564aae2014-10-23 10:18:09 -07001534 public int getNetworkTypeForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001535 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001536 }
1537
1538 /**
1539 * Returns the data network type
1540 */
1541 @Override
1542 public int getDataNetworkType() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001543 return getDataNetworkTypeForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001544 }
1545
1546 /**
1547 * Returns the data network type for a subId
1548 */
1549 @Override
Wink Savilleb564aae2014-10-23 10:18:09 -07001550 public int getDataNetworkTypeForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001551 return getPhone(subId).getServiceState().getDataNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001552 }
1553
1554 /**
1555 * Returns the data network type
1556 */
1557 @Override
1558 public int getVoiceNetworkType() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001559 return getVoiceNetworkTypeForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001560 }
1561
1562 /**
1563 * Returns the Voice network type for a subId
1564 */
1565 @Override
Wink Savilleb564aae2014-10-23 10:18:09 -07001566 public int getVoiceNetworkTypeForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001567 return getPhone(subId).getServiceState().getVoiceNetworkType();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001568 }
1569
1570 /**
1571 * @return true if a ICC card is present
1572 */
1573 public boolean hasIccCard() {
Wink Saville36469e72014-06-11 15:17:00 -07001574 // FIXME Make changes to pass defaultSimId of type int
1575 return hasIccCardUsingSlotId(getDefaultSubscription());
1576 }
1577
1578 /**
1579 * @return true if a ICC card is present for a slotId
1580 */
Wink Savilleb564aae2014-10-23 10:18:09 -07001581 public boolean hasIccCardUsingSlotId(int slotId) {
Wink Saville36469e72014-06-11 15:17:00 -07001582 return getPhone(slotId).getIccCard().hasIccCard();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001583 }
1584
1585 /**
1586 * Return if the current radio is LTE on CDMA. This
1587 * is a tri-state return value as for a period of time
1588 * the mode may be unknown.
1589 *
1590 * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
Jake Hambye994d462014-02-03 13:10:13 -08001591 * or {@link Phone#LTE_ON_CDMA_TRUE}
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001592 */
1593 public int getLteOnCdmaMode() {
Wink Savilleadd7cc52014-09-08 14:23:09 -07001594 return getLteOnCdmaModeForSubscriber(getDefaultSubscription());
Wink Saville36469e72014-06-11 15:17:00 -07001595 }
1596
Wink Savilleb564aae2014-10-23 10:18:09 -07001597 public int getLteOnCdmaModeForSubscriber(int subId) {
Wink Saville36469e72014-06-11 15:17:00 -07001598 return getPhone(subId).getLteOnCdmaMode();
1599 }
1600
1601 public void setPhone(Phone phone) {
1602 mPhone = phone;
1603 }
1604
1605 /**
1606 * {@hide}
1607 * Returns Default subId, 0 in the case of single standby.
1608 */
Wink Savilleb564aae2014-10-23 10:18:09 -07001609 private int getDefaultSubscription() {
Wink Savilleac1bdfd2014-11-20 23:04:44 -08001610 return mSubscriptionController.getDefaultSubId();
Wink Saville36469e72014-06-11 15:17:00 -07001611 }
1612
Wink Savilleb564aae2014-10-23 10:18:09 -07001613 private int getPreferredVoiceSubscription() {
Wink Savilleac1bdfd2014-11-20 23:04:44 -08001614 return mSubscriptionController.getDefaultVoiceSubId();
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001615 }
Ihab Awadf2177b72013-11-25 13:33:23 -08001616
1617 /**
1618 * @see android.telephony.TelephonyManager.WifiCallingChoices
1619 */
1620 public int getWhenToMakeWifiCalls() {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001621 return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1622 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
Ihab Awadf2177b72013-11-25 13:33:23 -08001623 }
1624
1625 /**
1626 * @see android.telephony.TelephonyManager.WifiCallingChoices
1627 */
1628 public void setWhenToMakeWifiCalls(int preference) {
Sailesh Nepald1e68152013-12-12 19:08:02 -08001629 if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1630 Settings.System.putInt(mPhone.getContext().getContentResolver(),
1631 Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
Ihab Awadf9e92732013-12-05 18:02:52 -08001632 }
1633
Sailesh Nepald1e68152013-12-12 19:08:02 -08001634 private static int getWhenToMakeWifiCallsDefaultPreference() {
Santos Cordonda120f42014-08-06 04:44:34 -07001635 // TODO: Use a build property to choose this value.
Evan Charlton9829e882013-12-19 15:30:38 -08001636 return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
Ihab Awadf2177b72013-11-25 13:33:23 -08001637 }
Shishir Agrawal69f68122013-12-16 17:25:49 -08001638
Shishir Agrawal566b7612013-10-28 14:41:00 -07001639 @Override
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001640 public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID) {
Junda Liua2e36012014-07-09 18:30:01 -07001641 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001642
1643 if (DBG) log("iccOpenLogicalChannel: " + AID);
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001644 IccOpenLogicalChannelResponse response = (IccOpenLogicalChannelResponse)sendRequest(
1645 CMD_OPEN_CHANNEL, AID);
1646 if (DBG) log("iccOpenLogicalChannel: " + response);
1647 return response;
Shishir Agrawal566b7612013-10-28 14:41:00 -07001648 }
1649
1650 @Override
1651 public boolean iccCloseLogicalChannel(int channel) {
Junda Liua2e36012014-07-09 18:30:01 -07001652 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001653
1654 if (DBG) log("iccCloseLogicalChannel: " + channel);
1655 if (channel < 0) {
1656 return false;
1657 }
Jake Hambye994d462014-02-03 13:10:13 -08001658 Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
Shishir Agrawal566b7612013-10-28 14:41:00 -07001659 if (DBG) log("iccCloseLogicalChannel: " + success);
1660 return success;
1661 }
1662
1663 @Override
1664 public String iccTransmitApduLogicalChannel(int channel, int cla,
1665 int command, int p1, int p2, int p3, String data) {
Junda Liua2e36012014-07-09 18:30:01 -07001666 enforceModifyPermissionOrCarrierPrivilege();
Shishir Agrawal566b7612013-10-28 14:41:00 -07001667
1668 if (DBG) {
1669 log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1670 " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1671 " data=" + data);
1672 }
1673
1674 if (channel < 0) {
1675 return "";
1676 }
1677
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001678 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_LOGICAL_CHANNEL,
Shishir Agrawal566b7612013-10-28 14:41:00 -07001679 new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1680 if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1681
Shishir Agrawal566b7612013-10-28 14:41:00 -07001682 // Append the returned status code to the end of the response payload.
1683 String s = Integer.toHexString(
1684 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
Shishir Agrawal5ec14172014-08-05 17:05:45 -07001685 if (response.payload != null) {
1686 s = IccUtils.bytesToHexString(response.payload) + s;
1687 }
Shishir Agrawal566b7612013-10-28 14:41:00 -07001688 return s;
1689 }
Jake Hambye994d462014-02-03 13:10:13 -08001690
Evan Charltonc66da362014-05-16 14:06:40 -07001691 @Override
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001692 public String iccTransmitApduBasicChannel(int cla, int command, int p1, int p2,
1693 int p3, String data) {
1694 enforceModifyPermissionOrCarrierPrivilege();
1695
1696 if (DBG) {
1697 log("iccTransmitApduBasicChannel: cla=" + cla + " cmd=" + command + " p1="
1698 + p1 + " p2=" + p2 + " p3=" + p3 + " data=" + data);
1699 }
1700
1701 IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_BASIC_CHANNEL,
1702 new IccAPDUArgument(0, cla, command, p1, p2, p3, data));
1703 if (DBG) log("iccTransmitApduBasicChannel: " + response);
1704
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001705 // Append the returned status code to the end of the response payload.
1706 String s = Integer.toHexString(
1707 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
Shishir Agrawal5ec14172014-08-05 17:05:45 -07001708 if (response.payload != null) {
1709 s = IccUtils.bytesToHexString(response.payload) + s;
1710 }
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001711 return s;
1712 }
1713
1714 @Override
1715 public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
1716 String filePath) {
1717 enforceModifyPermissionOrCarrierPrivilege();
1718
1719 if (DBG) {
1720 log("Exchange SIM_IO " + fileID + ":" + command + " " +
1721 p1 + " " + p2 + " " + p3 + ":" + filePath);
1722 }
1723
1724 IccIoResult response =
1725 (IccIoResult)sendRequest(CMD_EXCHANGE_SIM_IO,
Yong Jiang3edf3782014-10-03 13:23:28 -05001726 new IccAPDUArgument(-1, fileID, command, p1, p2, p3, filePath));
Shishir Agrawalda0bb0d2014-07-29 21:18:53 -07001727
1728 if (DBG) {
1729 log("Exchange SIM_IO [R]" + response);
1730 }
1731
1732 byte[] result = null;
1733 int length = 2;
1734 if (response.payload != null) {
1735 length = 2 + response.payload.length;
1736 result = new byte[length];
1737 System.arraycopy(response.payload, 0, result, 0, response.payload.length);
1738 } else {
1739 result = new byte[length];
1740 }
1741
1742 result[length - 1] = (byte) response.sw2;
1743 result[length - 2] = (byte) response.sw1;
1744 return result;
1745 }
1746
1747 @Override
Evan Charltonc66da362014-05-16 14:06:40 -07001748 public String sendEnvelopeWithStatus(String content) {
Junda Liua2e36012014-07-09 18:30:01 -07001749 enforceModifyPermissionOrCarrierPrivilege();
Evan Charltonc66da362014-05-16 14:06:40 -07001750
1751 IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
1752 if (response.payload == null) {
1753 return "";
1754 }
1755
1756 // Append the returned status code to the end of the response payload.
1757 String s = Integer.toHexString(
1758 (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1759 s = IccUtils.bytesToHexString(response.payload) + s;
1760 return s;
1761 }
1762
Jake Hambye994d462014-02-03 13:10:13 -08001763 /**
1764 * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1765 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1766 *
1767 * @param itemID the ID of the item to read
1768 * @return the NV item as a String, or null on error.
1769 */
1770 @Override
1771 public String nvReadItem(int itemID) {
Junda Liua2e36012014-07-09 18:30:01 -07001772 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001773 if (DBG) log("nvReadItem: item " + itemID);
1774 String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
1775 if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
1776 return value;
1777 }
1778
1779 /**
1780 * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1781 * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1782 *
1783 * @param itemID the ID of the item to read
1784 * @param itemValue the value to write, as a String
1785 * @return true on success; false on any failure
1786 */
1787 @Override
1788 public boolean nvWriteItem(int itemID, String itemValue) {
Junda Liua2e36012014-07-09 18:30:01 -07001789 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001790 if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
1791 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
1792 new Pair<Integer, String>(itemID, itemValue));
1793 if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
1794 return success;
1795 }
1796
1797 /**
1798 * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
1799 * Used for device configuration by some CDMA operators.
1800 *
1801 * @param preferredRoamingList byte array containing the new PRL
1802 * @return true on success; false on any failure
1803 */
1804 @Override
1805 public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
Junda Liua2e36012014-07-09 18:30:01 -07001806 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001807 if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
1808 Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
1809 if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
1810 return success;
1811 }
1812
1813 /**
1814 * Perform the specified type of NV config reset.
1815 * Used for device configuration by some CDMA operators.
1816 *
1817 * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
1818 * @return true on success; false on any failure
1819 */
1820 @Override
1821 public boolean nvResetConfig(int resetType) {
Junda Liua2e36012014-07-09 18:30:01 -07001822 enforceModifyPermissionOrCarrierPrivilege();
Jake Hambye994d462014-02-03 13:10:13 -08001823 if (DBG) log("nvResetConfig: type " + resetType);
1824 Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
1825 if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
1826 return success;
1827 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001828
1829 /**
Wink Saville36469e72014-06-11 15:17:00 -07001830 * {@hide}
1831 * Returns Default sim, 0 in the case of single standby.
1832 */
1833 public int getDefaultSim() {
1834 //TODO Need to get it from Telephony Devcontroller
1835 return 0;
1836 }
1837
ram87fca6f2014-07-18 18:58:44 +05301838 public String[] getPcscfAddress(String apnType) {
Wink Saville36469e72014-06-11 15:17:00 -07001839 enforceReadPermission();
ram87fca6f2014-07-18 18:58:44 +05301840 return mPhone.getPcscfAddress(apnType);
Wink Saville36469e72014-06-11 15:17:00 -07001841 }
1842
1843 public void setImsRegistrationState(boolean registered) {
1844 enforceModifyPermission();
1845 mPhone.setImsRegistrationState(registered);
1846 }
1847
1848 /**
Junda Liu84d15a22014-07-02 11:21:04 -07001849 * Get the calculated preferred network type.
1850 * Used for debugging incorrect network type.
1851 *
1852 * @return the preferred network type, defined in RILConstants.java.
1853 */
1854 @Override
1855 public int getCalculatedPreferredNetworkType() {
1856 enforceReadPermission();
Amit Mahajan43330e02014-11-18 11:54:45 -08001857 return PhoneFactory.calculatePreferredNetworkType(mPhone.getContext(), 0); // wink FIXME: need to get SubId from somewhere.
Junda Liu84d15a22014-07-02 11:21:04 -07001858 }
1859
1860 /**
Jake Hamby7c27be32014-03-03 13:25:59 -08001861 * Get the preferred network type.
1862 * Used for device configuration by some CDMA operators.
1863 *
1864 * @return the preferred network type, defined in RILConstants.java.
1865 */
1866 @Override
1867 public int getPreferredNetworkType() {
Junda Liua2e36012014-07-09 18:30:01 -07001868 enforceModifyPermissionOrCarrierPrivilege();
Jake Hamby7c27be32014-03-03 13:25:59 -08001869 if (DBG) log("getPreferredNetworkType");
1870 int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null);
1871 int networkType = (result != null ? result[0] : -1);
1872 if (DBG) log("getPreferredNetworkType: " + networkType);
1873 return networkType;
1874 }
1875
1876 /**
1877 * Set the preferred network type.
1878 * Used for device configuration by some CDMA operators.
1879 *
1880 * @param networkType the preferred network type, defined in RILConstants.java.
1881 * @return true on success; false on any failure.
1882 */
1883 @Override
1884 public boolean setPreferredNetworkType(int networkType) {
Junda Liua2e36012014-07-09 18:30:01 -07001885 enforceModifyPermissionOrCarrierPrivilege();
PauloftheWest3c6ce5e2014-11-03 07:09:47 -08001886 final int phoneSubId = mPhone.getSubId();
Jake Hamby7c27be32014-03-03 13:25:59 -08001887 if (DBG) log("setPreferredNetworkType: type " + networkType);
1888 Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType);
1889 if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
Junda Liu80bc0d12014-07-14 16:36:44 -07001890 if (success) {
1891 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
PauloftheWest3c6ce5e2014-11-03 07:09:47 -08001892 Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId, networkType);
Junda Liu80bc0d12014-07-14 16:36:44 -07001893 }
Jake Hamby7c27be32014-03-03 13:25:59 -08001894 return success;
1895 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001896
1897 /**
Junda Liu475951f2014-11-07 16:45:03 -08001898 * Check TETHER_DUN_REQUIRED and TETHER_DUN_APN settings, net.tethering.noprovisioning
1899 * SystemProperty, and config_tether_apndata to decide whether DUN APN is required for
1900 * tethering.
1901 *
1902 * @return 0: Not required. 1: required. 2: Not set.
1903 * @hide
1904 */
1905 @Override
1906 public int getTetherApnRequired() {
1907 enforceModifyPermissionOrCarrierPrivilege();
1908 int dunRequired = Settings.Global.getInt(mPhone.getContext().getContentResolver(),
1909 Settings.Global.TETHER_DUN_REQUIRED, 2);
1910 // If not set, check net.tethering.noprovisioning, TETHER_DUN_APN setting and
1911 // config_tether_apndata.
1912 if (dunRequired == 2 && mPhone.hasMatchedTetherApnSetting()) {
1913 dunRequired = 1;
1914 }
1915 return dunRequired;
1916 }
1917
1918 /**
Robert Greenwalted86e582014-05-21 20:03:20 -07001919 * Set mobile data enabled
1920 * Used by the user through settings etc to turn on/off mobile data
1921 *
1922 * @param enable {@code true} turn turn data on, else {@code false}
1923 */
1924 @Override
Wink Savillee7353bb2014-12-05 14:21:41 -08001925 public void setDataEnabled(int subId, boolean enable) {
Robert Greenwalted86e582014-05-21 20:03:20 -07001926 enforceModifyPermission();
Wink Savillee7353bb2014-12-05 14:21:41 -08001927 int phoneId = mSubscriptionController.getPhoneId(subId);
1928 log("getDataEnabled: subId=" + subId + " phoneId=" + phoneId);
1929 Phone phone = PhoneFactory.getPhone(phoneId);
1930 if (phone != null) {
1931 log("setDataEnabled: subId=" + subId + " enable=" + enable);
1932 phone.setDataEnabled(enable);
1933 } else {
1934 loge("setDataEnabled: no phone for subId=" + subId);
1935 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001936 }
1937
1938 /**
Robert Greenwalt646120a2014-05-23 11:54:03 -07001939 * Get whether mobile data is enabled.
1940 *
1941 * Note that this used to be available from ConnectivityService, gated by
1942 * ACCESS_NETWORK_STATE permission, so this will accept either that or
1943 * our MODIFY_PHONE_STATE.
Robert Greenwalted86e582014-05-21 20:03:20 -07001944 *
1945 * @return {@code true} if data is enabled else {@code false}
1946 */
1947 @Override
Wink Savillee7353bb2014-12-05 14:21:41 -08001948 public boolean getDataEnabled(int subId) {
Robert Greenwalt646120a2014-05-23 11:54:03 -07001949 try {
1950 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
1951 null);
1952 } catch (Exception e) {
1953 mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
1954 null);
1955 }
Wink Savillee7353bb2014-12-05 14:21:41 -08001956 int phoneId = mSubscriptionController.getPhoneId(subId);
1957 log("getDataEnabled: subId=" + subId + " phoneId=" + phoneId);
1958 Phone phone = PhoneFactory.getPhone(phoneId);
1959 if (phone != null) {
1960 boolean retVal = phone.getDataEnabled();
1961 log("getDataEnabled: subId=" + subId + " retVal=" + retVal);
1962 return retVal;
1963 } else {
1964 loge("getDataEnabled: no phone subId=" + subId + " retVal=false");
1965 return false;
1966 }
Robert Greenwalted86e582014-05-21 20:03:20 -07001967 }
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001968
1969 @Override
Shishir Agrawal5e5becd2014-11-18 11:38:23 -08001970 public int getCarrierPrivilegeStatus() {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001971 UiccCard card = UiccController.getInstance().getUiccCard();
1972 if (card == null) {
Shishir Agrawal5e5becd2014-11-18 11:38:23 -08001973 loge("getCarrierPrivilegeStatus: No UICC");
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001974 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1975 }
1976 return card.getCarrierPrivilegeStatusForCurrentTransaction(
Shishir Agrawalf1ac4c92014-07-14 13:54:28 -07001977 mPhone.getContext().getPackageManager());
Shishir Agrawal60f9c952014-06-23 12:00:43 -07001978 }
Junda Liu29340342014-07-10 15:23:27 -07001979
1980 @Override
Shishir Agrawal6d5a2852014-07-11 16:32:57 -07001981 public int checkCarrierPrivilegesForPackage(String pkgname) {
Shishir Agrawaleb8771e2014-07-22 11:24:08 -07001982 UiccCard card = UiccController.getInstance().getUiccCard();
1983 if (card == null) {
1984 loge("checkCarrierPrivilegesForPackage: No UICC");
1985 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
1986 }
1987 return card.getCarrierPrivilegeStatus(mPhone.getContext().getPackageManager(), pkgname);
Junda Liu29340342014-07-10 15:23:27 -07001988 }
Derek Tan89e89d42014-07-08 17:00:10 -07001989
1990 @Override
Diego Pontorieroaf74c862014-08-28 11:51:16 -07001991 public List<String> getCarrierPackageNamesForIntent(Intent intent) {
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001992 UiccCard card = UiccController.getInstance().getUiccCard();
1993 if (card == null) {
Diego Pontorieroaf74c862014-08-28 11:51:16 -07001994 loge("getCarrierPackageNamesForIntent: No UICC");
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001995 return null ;
1996 }
Diego Pontorieroaf74c862014-08-28 11:51:16 -07001997 return card.getCarrierPackageNamesForIntent(
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07001998 mPhone.getContext().getPackageManager(), intent);
1999 }
2000
Wink Savilleb564aae2014-10-23 10:18:09 -07002001 private String getIccId(int subId) {
Derek Tan97ebb422014-09-05 16:55:38 -07002002 UiccCard card = getPhone(subId).getUiccCard();
2003 if (card == null) {
2004 loge("getIccId: No UICC");
2005 return null;
2006 }
2007 String iccId = card.getIccId();
2008 if (TextUtils.isEmpty(iccId)) {
2009 loge("getIccId: ICC ID is null or empty.");
2010 return null;
2011 }
2012 return iccId;
2013 }
2014
Shishir Agrawaleb6439a2014-07-21 13:19:38 -07002015 @Override
Jeff Sharkey85190e62014-12-05 09:40:12 -08002016 public boolean setLine1NumberForDisplayForSubscriber(int subId, String alphaTag,
2017 String number) {
Shishir Agrawal5e5becd2014-11-18 11:38:23 -08002018 enforceCarrierPrivilege();
Derek Tan97ebb422014-09-05 16:55:38 -07002019
Jeff Sharkey85190e62014-12-05 09:40:12 -08002020 final String iccId = getIccId(subId);
2021 final String subscriberId = getPhone(subId).getSubscriberId();
2022
2023 if (DBG_MERGE) {
2024 Slog.d(LOG_TAG, "Setting line number for ICC=" + iccId + ", subscriberId="
2025 + subscriberId + " to " + number);
2026 }
2027
Shishir Agrawal495d7e12014-12-01 11:50:28 -08002028 if (TextUtils.isEmpty(iccId)) {
2029 return false;
Derek Tan97ebb422014-09-05 16:55:38 -07002030 }
Shishir Agrawal495d7e12014-12-01 11:50:28 -08002031
Jeff Sharkey85190e62014-12-05 09:40:12 -08002032 final SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
2033
2034 final String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
Shishir Agrawal495d7e12014-12-01 11:50:28 -08002035 if (alphaTag == null) {
2036 editor.remove(alphaTagPrefKey);
2037 } else {
2038 editor.putString(alphaTagPrefKey, alphaTag);
2039 }
2040
Jeff Sharkey85190e62014-12-05 09:40:12 -08002041 // Record both the line number and IMSI for this ICCID, since we need to
2042 // track all merged IMSIs based on line number
2043 final String numberPrefKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
2044 final String subscriberPrefKey = PREF_CARRIERS_SUBSCRIBER_PREFIX + iccId;
Shishir Agrawal495d7e12014-12-01 11:50:28 -08002045 if (number == null) {
2046 editor.remove(numberPrefKey);
Jeff Sharkey85190e62014-12-05 09:40:12 -08002047 editor.remove(subscriberPrefKey);
Shishir Agrawal495d7e12014-12-01 11:50:28 -08002048 } else {
2049 editor.putString(numberPrefKey, number);
Jeff Sharkey85190e62014-12-05 09:40:12 -08002050 editor.putString(subscriberPrefKey, subscriberId);
Shishir Agrawal495d7e12014-12-01 11:50:28 -08002051 }
Jeff Sharkey85190e62014-12-05 09:40:12 -08002052
Shishir Agrawal495d7e12014-12-01 11:50:28 -08002053 editor.commit();
2054 return true;
Derek Tan7226c842014-07-02 17:42:23 -07002055 }
2056
2057 @Override
Wink Savilleb564aae2014-10-23 10:18:09 -07002058 public String getLine1NumberForDisplay(int subId) {
Derek Tan7226c842014-07-02 17:42:23 -07002059 enforceReadPermission();
Derek Tan97ebb422014-09-05 16:55:38 -07002060
2061 String iccId = getIccId(subId);
2062 if (iccId != null) {
2063 String numberPrefKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
Andrew Leedf14ead2014-10-17 14:22:52 -07002064 return mTelephonySharedPreferences.getString(numberPrefKey, null);
Derek Tan7226c842014-07-02 17:42:23 -07002065 }
Derek Tan97ebb422014-09-05 16:55:38 -07002066 return null;
Derek Tan7226c842014-07-02 17:42:23 -07002067 }
2068
2069 @Override
Wink Savilleb564aae2014-10-23 10:18:09 -07002070 public String getLine1AlphaTagForDisplay(int subId) {
Derek Tan7226c842014-07-02 17:42:23 -07002071 enforceReadPermission();
Derek Tan97ebb422014-09-05 16:55:38 -07002072
2073 String iccId = getIccId(subId);
2074 if (iccId != null) {
2075 String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
Andrew Leedf14ead2014-10-17 14:22:52 -07002076 return mTelephonySharedPreferences.getString(alphaTagPrefKey, null);
Derek Tan7226c842014-07-02 17:42:23 -07002077 }
Derek Tan97ebb422014-09-05 16:55:38 -07002078 return null;
Derek Tan7226c842014-07-02 17:42:23 -07002079 }
Shishir Agrawalb1ebf8c2014-07-17 16:32:41 -07002080
2081 @Override
Jeff Sharkey85190e62014-12-05 09:40:12 -08002082 public String[] getMergedSubscriberIds() {
2083 final Context context = mPhone.getContext();
2084 final TelephonyManager tele = TelephonyManager.from(context);
2085 final SubscriptionManager sub = SubscriptionManager.from(context);
2086
2087 // Figure out what subscribers are currently active
2088 final ArraySet<String> activeSubscriberIds = new ArraySet<>();
2089 final int[] subIds = sub.getActiveSubscriptionIdList();
2090 for (int subId : subIds) {
2091 activeSubscriberIds.add(tele.getSubscriberId(subId));
2092 }
2093
2094 // First pass, find a number override for an active subscriber
2095 String mergeNumber = null;
2096 final Map<String, ?> prefs = mTelephonySharedPreferences.getAll();
2097 for (String key : prefs.keySet()) {
2098 if (key.startsWith(PREF_CARRIERS_SUBSCRIBER_PREFIX)) {
2099 final String subscriberId = (String) prefs.get(key);
2100 if (activeSubscriberIds.contains(subscriberId)) {
2101 final String iccId = key.substring(PREF_CARRIERS_SUBSCRIBER_PREFIX.length());
2102 final String numberKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
2103 mergeNumber = (String) prefs.get(numberKey);
2104 if (DBG_MERGE) {
2105 Slog.d(LOG_TAG, "Found line number " + mergeNumber
2106 + " for active subscriber " + subscriberId);
2107 }
2108 if (!TextUtils.isEmpty(mergeNumber)) {
2109 break;
2110 }
2111 }
2112 }
2113 }
2114
2115 // Shortcut when no active merged subscribers
2116 if (TextUtils.isEmpty(mergeNumber)) {
2117 return null;
2118 }
2119
2120 // Second pass, find all subscribers under that line override
2121 final ArraySet<String> result = new ArraySet<>();
2122 for (String key : prefs.keySet()) {
2123 if (key.startsWith(PREF_CARRIERS_NUMBER_PREFIX)) {
2124 final String number = (String) prefs.get(key);
2125 if (mergeNumber.equals(number)) {
2126 final String iccId = key.substring(PREF_CARRIERS_NUMBER_PREFIX.length());
2127 final String subscriberKey = PREF_CARRIERS_SUBSCRIBER_PREFIX + iccId;
2128 final String subscriberId = (String) prefs.get(subscriberKey);
2129 if (!TextUtils.isEmpty(subscriberId)) {
2130 result.add(subscriberId);
2131 }
2132 }
2133 }
2134 }
2135
2136 final String[] resultArray = result.toArray(new String[result.size()]);
2137 Arrays.sort(resultArray);
2138 if (DBG_MERGE) {
2139 Slog.d(LOG_TAG, "Found subscribers " + Arrays.toString(resultArray) + " after merge");
2140 }
2141 return resultArray;
2142 }
2143
2144 @Override
Shishir Agrawala3dfd752014-09-04 13:25:42 -07002145 public boolean setOperatorBrandOverride(String brand) {
Shishir Agrawal5e5becd2014-11-18 11:38:23 -08002146 enforceCarrierPrivilege();
Shishir Agrawala3dfd752014-09-04 13:25:42 -07002147 return mPhone.setOperatorBrandOverride(brand);
Shishir Agrawalb1ebf8c2014-07-17 16:32:41 -07002148 }
Steven Liu4bf01bc2014-07-17 11:05:29 -05002149
2150 @Override
2151 public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
2152 enforceModifyPermission();
2153
2154 int returnValue = 0;
2155 try {
2156 AsyncResult result = (AsyncResult)sendRequest(CMD_INVOKE_OEM_RIL_REQUEST_RAW, oemReq);
2157 if(result.exception == null) {
2158 if (result.result != null) {
2159 byte[] responseData = (byte[])(result.result);
2160 if(responseData.length > oemResp.length) {
2161 Log.w(LOG_TAG, "Buffer to copy response too small: Response length is " +
2162 responseData.length + "bytes. Buffer Size is " +
2163 oemResp.length + "bytes.");
2164 }
2165 System.arraycopy(responseData, 0, oemResp, 0, responseData.length);
2166 returnValue = responseData.length;
2167 }
2168 } else {
2169 CommandException ex = (CommandException) result.exception;
2170 returnValue = ex.getCommandError().ordinal();
2171 if(returnValue > 0) returnValue *= -1;
2172 }
2173 } catch (RuntimeException e) {
2174 Log.w(LOG_TAG, "sendOemRilRequestRaw: Runtime Exception");
2175 returnValue = (CommandException.Error.GENERIC_FAILURE.ordinal());
2176 if(returnValue > 0) returnValue *= -1;
2177 }
2178
2179 return returnValue;
2180 }
Wink Saville5d475dd2014-10-17 15:00:58 -07002181
2182 @Override
2183 public void setRadioCapability(RadioAccessFamily[] rafs) {
2184 try {
2185 ProxyController.getInstance().setRadioCapability(rafs);
2186 } catch (RuntimeException e) {
2187 Log.w(LOG_TAG, "setRadioCapability: Runtime Exception");
2188 }
2189 }
2190
2191 @Override
2192 public int getRadioAccessFamily(int phoneId) {
2193 return ProxyController.getInstance().getRadioAccessFamily(phoneId);
2194 }
Andrew Leedf14ead2014-10-17 14:22:52 -07002195
2196 @Override
2197 public void enableVideoCalling(boolean enable) {
2198 enforceModifyPermission();
2199 SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
2200 editor.putBoolean(PREF_ENABLE_VIDEO_CALLING, enable);
2201 editor.commit();
2202 }
2203
2204 @Override
2205 public boolean isVideoCallingEnabled() {
2206 enforceReadPermission();
Andrew Lee77527ac2014-10-21 16:57:39 -07002207 // Check the user preference and the system-level IMS setting. Even if the user has
2208 // enabled video calling, if IMS is disabled we aren't able to support video calling.
2209 // In the long run, we may instead need to check if there exists a connection service
2210 // which can support video calling.
Andrew Lee312e8172014-10-23 17:01:36 -07002211 return ImsManager.isVtEnabledByPlatform(mPhone.getContext())
2212 && ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mPhone.getContext())
2213 && mTelephonySharedPreferences.getBoolean(PREF_ENABLE_VIDEO_CALLING, true);
Andrew Leedf14ead2014-10-17 14:22:52 -07002214 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -07002215}