PhoneInterfaceManager.java revision 50ecba360335a12252c30c95c309ef3ff5560fbf
1/*
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;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.SharedPreferences;
25import android.content.pm.PackageManager;
26import 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;
36import android.os.UserManager;
37import android.preference.PreferenceManager;
38import android.provider.Settings;
39import android.telecom.PhoneAccount;
40import android.telecom.TelecomManager;
41import android.telephony.CarrierConfigManager;
42import android.telephony.CellInfo;
43import android.telephony.IccOpenLogicalChannelResponse;
44import android.telephony.NeighboringCellInfo;
45import android.telephony.RadioAccessFamily;
46import android.telephony.ServiceState;
47import android.telephony.SubscriptionInfo;
48import android.telephony.SubscriptionManager;
49import android.telephony.TelephonyManager;
50import android.text.TextUtils;
51import android.util.ArrayMap;
52import android.util.ArraySet;
53import android.util.Log;
54import android.util.Pair;
55import android.util.Slog;
56
57import com.android.ims.ImsManager;
58import com.android.internal.telephony.CallManager;
59import com.android.internal.telephony.CommandException;
60import com.android.internal.telephony.DefaultPhoneNotifier;
61import com.android.internal.telephony.ITelephony;
62import com.android.internal.telephony.IccCard;
63import com.android.internal.telephony.MccTable;
64import com.android.internal.telephony.Phone;
65import com.android.internal.telephony.PhoneFactory;
66import com.android.internal.telephony.ProxyController;
67import com.android.internal.telephony.PhoneConstants;
68import com.android.internal.telephony.RILConstants;
69import com.android.internal.telephony.SubscriptionController;
70import com.android.internal.telephony.uicc.IccIoResult;
71import com.android.internal.telephony.uicc.IccUtils;
72import com.android.internal.telephony.uicc.UiccCard;
73import com.android.internal.telephony.uicc.UiccController;
74import com.android.internal.util.HexDump;
75
76import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
77
78import java.util.ArrayList;
79import java.util.Arrays;
80import java.util.HashMap;
81import java.util.Iterator;
82import java.util.List;
83import java.util.Locale;
84import java.util.Map;
85import java.util.Objects;
86
87/**
88 * Implementation of the ITelephony interface.
89 */
90public class PhoneInterfaceManager extends ITelephony.Stub {
91    private static final String LOG_TAG = "PhoneInterfaceManager";
92    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
93    private static final boolean DBG_LOC = false;
94    private static final boolean DBG_MERGE = false;
95
96    // Message codes used with mMainThreadHandler
97    private static final int CMD_HANDLE_PIN_MMI = 1;
98    private static final int CMD_HANDLE_NEIGHBORING_CELL = 2;
99    private static final int EVENT_NEIGHBORING_CELL_DONE = 3;
100    private static final int CMD_ANSWER_RINGING_CALL = 4;
101    private static final int CMD_END_CALL = 5;  // not used yet
102    private static final int CMD_TRANSMIT_APDU_LOGICAL_CHANNEL = 7;
103    private static final int EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE = 8;
104    private static final int CMD_OPEN_CHANNEL = 9;
105    private static final int EVENT_OPEN_CHANNEL_DONE = 10;
106    private static final int CMD_CLOSE_CHANNEL = 11;
107    private static final int EVENT_CLOSE_CHANNEL_DONE = 12;
108    private static final int CMD_NV_READ_ITEM = 13;
109    private static final int EVENT_NV_READ_ITEM_DONE = 14;
110    private static final int CMD_NV_WRITE_ITEM = 15;
111    private static final int EVENT_NV_WRITE_ITEM_DONE = 16;
112    private static final int CMD_NV_WRITE_CDMA_PRL = 17;
113    private static final int EVENT_NV_WRITE_CDMA_PRL_DONE = 18;
114    private static final int CMD_NV_RESET_CONFIG = 19;
115    private static final int EVENT_NV_RESET_CONFIG_DONE = 20;
116    private static final int CMD_GET_PREFERRED_NETWORK_TYPE = 21;
117    private static final int EVENT_GET_PREFERRED_NETWORK_TYPE_DONE = 22;
118    private static final int CMD_SET_PREFERRED_NETWORK_TYPE = 23;
119    private static final int EVENT_SET_PREFERRED_NETWORK_TYPE_DONE = 24;
120    private static final int CMD_SEND_ENVELOPE = 25;
121    private static final int EVENT_SEND_ENVELOPE_DONE = 26;
122    private static final int CMD_INVOKE_OEM_RIL_REQUEST_RAW = 27;
123    private static final int EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE = 28;
124    private static final int CMD_TRANSMIT_APDU_BASIC_CHANNEL = 29;
125    private static final int EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE = 30;
126    private static final int CMD_EXCHANGE_SIM_IO = 31;
127    private static final int EVENT_EXCHANGE_SIM_IO_DONE = 32;
128    private static final int CMD_SET_VOICEMAIL_NUMBER = 33;
129    private static final int EVENT_SET_VOICEMAIL_NUMBER_DONE = 34;
130    private static final int CMD_SET_NETWORK_SELECTION_MODE_AUTOMATIC = 35;
131    private static final int EVENT_SET_NETWORK_SELECTION_MODE_AUTOMATIC_DONE = 36;
132
133    /** The singleton instance. */
134    private static PhoneInterfaceManager sInstance;
135
136    private PhoneGlobals mApp;
137    private Phone mPhone;
138    private CallManager mCM;
139    private UserManager mUserManager;
140    private AppOpsManager mAppOps;
141    private MainThreadHandler mMainThreadHandler;
142    private SubscriptionController mSubscriptionController;
143    private SharedPreferences mTelephonySharedPreferences;
144
145    private static final String PREF_CARRIERS_ALPHATAG_PREFIX = "carrier_alphtag_";
146    private static final String PREF_CARRIERS_NUMBER_PREFIX = "carrier_number_";
147    private static final String PREF_CARRIERS_SUBSCRIBER_PREFIX = "carrier_subscriber_";
148    private static final String PREF_ENABLE_VIDEO_CALLING = "enable_video_calling";
149
150    /**
151     * A request object to use for transmitting data to an ICC.
152     */
153    private static final class IccAPDUArgument {
154        public int channel, cla, command, p1, p2, p3;
155        public String data;
156
157        public IccAPDUArgument(int channel, int cla, int command,
158                int p1, int p2, int p3, String data) {
159            this.channel = channel;
160            this.cla = cla;
161            this.command = command;
162            this.p1 = p1;
163            this.p2 = p2;
164            this.p3 = p3;
165            this.data = data;
166        }
167    }
168
169    /**
170     * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
171     * request after sending. The main thread will notify the request when it is complete.
172     */
173    private static final class MainThreadRequest {
174        /** The argument to use for the request */
175        public Object argument;
176        /** The result of the request that is run on the main thread */
177        public Object result;
178        /** The subscriber id that this request applies to. Null if default. */
179        public Integer subId;
180
181        public MainThreadRequest(Object argument) {
182            this.argument = argument;
183        }
184
185        public MainThreadRequest(Object argument, Integer subId) {
186            this.argument = argument;
187            this.subId = subId;
188        }
189    }
190
191    private static final class IncomingThirdPartyCallArgs {
192        public final ComponentName component;
193        public final String callId;
194        public final String callerDisplayName;
195
196        public IncomingThirdPartyCallArgs(ComponentName component, String callId,
197                String callerDisplayName) {
198            this.component = component;
199            this.callId = callId;
200            this.callerDisplayName = callerDisplayName;
201        }
202    }
203
204    /**
205     * A handler that processes messages on the main thread in the phone process. Since many
206     * of the Phone calls are not thread safe this is needed to shuttle the requests from the
207     * inbound binder threads to the main thread in the phone process.  The Binder thread
208     * may provide a {@link MainThreadRequest} object in the msg.obj field that they are waiting
209     * on, which will be notified when the operation completes and will contain the result of the
210     * request.
211     *
212     * <p>If a MainThreadRequest object is provided in the msg.obj field,
213     * note that request.result must be set to something non-null for the calling thread to
214     * unblock.
215     */
216    private final class MainThreadHandler extends Handler {
217        @Override
218        public void handleMessage(Message msg) {
219            MainThreadRequest request;
220            Message onCompleted;
221            AsyncResult ar;
222            UiccCard uiccCard = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
223            IccAPDUArgument iccArgument;
224
225            switch (msg.what) {
226                case CMD_HANDLE_PIN_MMI:
227                    request = (MainThreadRequest) msg.obj;
228                    request.result = getPhoneFromRequest(request).handlePinMmi(
229                            (String) request.argument);
230                    // Wake up the requesting thread
231                    synchronized (request) {
232                        request.notifyAll();
233                    }
234                    break;
235
236                case CMD_HANDLE_NEIGHBORING_CELL:
237                    request = (MainThreadRequest) msg.obj;
238                    onCompleted = obtainMessage(EVENT_NEIGHBORING_CELL_DONE,
239                            request);
240                    mPhone.getNeighboringCids(onCompleted);
241                    break;
242
243                case EVENT_NEIGHBORING_CELL_DONE:
244                    ar = (AsyncResult) msg.obj;
245                    request = (MainThreadRequest) ar.userObj;
246                    if (ar.exception == null && ar.result != null) {
247                        request.result = ar.result;
248                    } else {
249                        // create an empty list to notify the waiting thread
250                        request.result = new ArrayList<NeighboringCellInfo>(0);
251                    }
252                    // Wake up the requesting thread
253                    synchronized (request) {
254                        request.notifyAll();
255                    }
256                    break;
257
258                case CMD_ANSWER_RINGING_CALL:
259                    request = (MainThreadRequest) msg.obj;
260                    int answer_subId = request.subId;
261                    answerRingingCallInternal(answer_subId);
262                    break;
263
264                case CMD_END_CALL:
265                    request = (MainThreadRequest) msg.obj;
266                    int end_subId = request.subId;
267                    final boolean hungUp;
268                    Phone phone = getPhone(end_subId);
269                    if (phone == null) {
270                        if (DBG) log("CMD_END_CALL: no phone for id: " + end_subId);
271                        break;
272                    }
273                    int phoneType = phone.getPhoneType();
274                    if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
275                        // CDMA: If the user presses the Power button we treat it as
276                        // ending the complete call session
277                        hungUp = PhoneUtils.hangupRingingAndActive(getPhone(end_subId));
278                    } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
279                        // GSM: End the call as per the Phone state
280                        hungUp = PhoneUtils.hangup(mCM);
281                    } else {
282                        throw new IllegalStateException("Unexpected phone type: " + phoneType);
283                    }
284                    if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up"));
285                    request.result = hungUp;
286                    // Wake up the requesting thread
287                    synchronized (request) {
288                        request.notifyAll();
289                    }
290                    break;
291
292                case CMD_TRANSMIT_APDU_LOGICAL_CHANNEL:
293                    request = (MainThreadRequest) msg.obj;
294                    iccArgument = (IccAPDUArgument) request.argument;
295                    if (uiccCard == null) {
296                        loge("iccTransmitApduLogicalChannel: No UICC");
297                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
298                        synchronized (request) {
299                            request.notifyAll();
300                        }
301                    } else {
302                        onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE,
303                            request);
304                        uiccCard.iccTransmitApduLogicalChannel(
305                            iccArgument.channel, iccArgument.cla, iccArgument.command,
306                            iccArgument.p1, iccArgument.p2, iccArgument.p3, iccArgument.data,
307                            onCompleted);
308                    }
309                    break;
310
311                case EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE:
312                    ar = (AsyncResult) msg.obj;
313                    request = (MainThreadRequest) ar.userObj;
314                    if (ar.exception == null && ar.result != null) {
315                        request.result = ar.result;
316                    } else {
317                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
318                        if (ar.result == null) {
319                            loge("iccTransmitApduLogicalChannel: Empty response");
320                        } else if (ar.exception instanceof CommandException) {
321                            loge("iccTransmitApduLogicalChannel: CommandException: " +
322                                    ar.exception);
323                        } else {
324                            loge("iccTransmitApduLogicalChannel: Unknown exception");
325                        }
326                    }
327                    synchronized (request) {
328                        request.notifyAll();
329                    }
330                    break;
331
332                case CMD_TRANSMIT_APDU_BASIC_CHANNEL:
333                    request = (MainThreadRequest) msg.obj;
334                    iccArgument = (IccAPDUArgument) request.argument;
335                    if (uiccCard == null) {
336                        loge("iccTransmitApduBasicChannel: No UICC");
337                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
338                        synchronized (request) {
339                            request.notifyAll();
340                        }
341                    } else {
342                        onCompleted = obtainMessage(EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE,
343                            request);
344                        uiccCard.iccTransmitApduBasicChannel(
345                            iccArgument.cla, iccArgument.command, iccArgument.p1, iccArgument.p2,
346                            iccArgument.p3, iccArgument.data, onCompleted);
347                    }
348                    break;
349
350                case EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE:
351                    ar = (AsyncResult) msg.obj;
352                    request = (MainThreadRequest) ar.userObj;
353                    if (ar.exception == null && ar.result != null) {
354                        request.result = ar.result;
355                    } else {
356                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
357                        if (ar.result == null) {
358                            loge("iccTransmitApduBasicChannel: Empty response");
359                        } else if (ar.exception instanceof CommandException) {
360                            loge("iccTransmitApduBasicChannel: CommandException: " +
361                                    ar.exception);
362                        } else {
363                            loge("iccTransmitApduBasicChannel: Unknown exception");
364                        }
365                    }
366                    synchronized (request) {
367                        request.notifyAll();
368                    }
369                    break;
370
371                case CMD_EXCHANGE_SIM_IO:
372                    request = (MainThreadRequest) msg.obj;
373                    iccArgument = (IccAPDUArgument) request.argument;
374                    if (uiccCard == null) {
375                        loge("iccExchangeSimIO: No UICC");
376                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
377                        synchronized (request) {
378                            request.notifyAll();
379                        }
380                    } else {
381                        onCompleted = obtainMessage(EVENT_EXCHANGE_SIM_IO_DONE,
382                                request);
383                        uiccCard.iccExchangeSimIO(iccArgument.cla, /* fileID */
384                                iccArgument.command, iccArgument.p1, iccArgument.p2, iccArgument.p3,
385                                iccArgument.data, onCompleted);
386                    }
387                    break;
388
389                case EVENT_EXCHANGE_SIM_IO_DONE:
390                    ar = (AsyncResult) msg.obj;
391                    request = (MainThreadRequest) ar.userObj;
392                    if (ar.exception == null && ar.result != null) {
393                        request.result = ar.result;
394                    } else {
395                        request.result = new IccIoResult(0x6f, 0, (byte[])null);
396                    }
397                    synchronized (request) {
398                        request.notifyAll();
399                    }
400                    break;
401
402                case CMD_SEND_ENVELOPE:
403                    request = (MainThreadRequest) msg.obj;
404                    if (uiccCard == null) {
405                        loge("sendEnvelopeWithStatus: No UICC");
406                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
407                        synchronized (request) {
408                            request.notifyAll();
409                        }
410                    } else {
411                        onCompleted = obtainMessage(EVENT_SEND_ENVELOPE_DONE, request);
412                        uiccCard.sendEnvelopeWithStatus((String)request.argument, onCompleted);
413                    }
414                    break;
415
416                case EVENT_SEND_ENVELOPE_DONE:
417                    ar = (AsyncResult) msg.obj;
418                    request = (MainThreadRequest) ar.userObj;
419                    if (ar.exception == null && ar.result != null) {
420                        request.result = ar.result;
421                    } else {
422                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
423                        if (ar.result == null) {
424                            loge("sendEnvelopeWithStatus: Empty response");
425                        } else if (ar.exception instanceof CommandException) {
426                            loge("sendEnvelopeWithStatus: CommandException: " +
427                                    ar.exception);
428                        } else {
429                            loge("sendEnvelopeWithStatus: exception:" + ar.exception);
430                        }
431                    }
432                    synchronized (request) {
433                        request.notifyAll();
434                    }
435                    break;
436
437                case CMD_OPEN_CHANNEL:
438                    request = (MainThreadRequest) msg.obj;
439                    if (uiccCard == null) {
440                        loge("iccOpenLogicalChannel: No UICC");
441                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
442                        synchronized (request) {
443                            request.notifyAll();
444                        }
445                    } else {
446                        onCompleted = obtainMessage(EVENT_OPEN_CHANNEL_DONE, request);
447                        uiccCard.iccOpenLogicalChannel((String)request.argument, onCompleted);
448                    }
449                    break;
450
451                case EVENT_OPEN_CHANNEL_DONE:
452                    ar = (AsyncResult) msg.obj;
453                    request = (MainThreadRequest) ar.userObj;
454                    IccOpenLogicalChannelResponse openChannelResp;
455                    if (ar.exception == null && ar.result != null) {
456                        int[] result = (int[]) ar.result;
457                        int channelId = result[0];
458                        byte[] selectResponse = null;
459                        if (result.length > 1) {
460                            selectResponse = new byte[result.length - 1];
461                            for (int i = 1; i < result.length; ++i) {
462                                selectResponse[i - 1] = (byte) result[i];
463                            }
464                        }
465                        openChannelResp = new IccOpenLogicalChannelResponse(channelId,
466                            IccOpenLogicalChannelResponse.STATUS_NO_ERROR, selectResponse);
467                    } else {
468                        if (ar.result == null) {
469                            loge("iccOpenLogicalChannel: Empty response");
470                        }
471                        if (ar.exception != null) {
472                            loge("iccOpenLogicalChannel: Exception: " + ar.exception);
473                        }
474
475                        int errorCode = IccOpenLogicalChannelResponse.STATUS_UNKNOWN_ERROR;
476                        if (ar.exception instanceof CommandException) {
477                            CommandException.Error error =
478                                ((CommandException) (ar.exception)).getCommandError();
479                            if (error == CommandException.Error.MISSING_RESOURCE) {
480                                errorCode = IccOpenLogicalChannelResponse.STATUS_MISSING_RESOURCE;
481                            } else if (error == CommandException.Error.NO_SUCH_ELEMENT) {
482                                errorCode = IccOpenLogicalChannelResponse.STATUS_NO_SUCH_ELEMENT;
483                            }
484                        }
485                        openChannelResp = new IccOpenLogicalChannelResponse(
486                            IccOpenLogicalChannelResponse.INVALID_CHANNEL, errorCode, null);
487                    }
488                    request.result = openChannelResp;
489                    synchronized (request) {
490                        request.notifyAll();
491                    }
492                    break;
493
494                case CMD_CLOSE_CHANNEL:
495                    request = (MainThreadRequest) msg.obj;
496                    if (uiccCard == null) {
497                        loge("iccCloseLogicalChannel: No UICC");
498                        request.result = new IccIoResult(0x6F, 0, (byte[])null);
499                        synchronized (request) {
500                            request.notifyAll();
501                        }
502                    } else {
503                        onCompleted = obtainMessage(EVENT_CLOSE_CHANNEL_DONE, request);
504                        uiccCard.iccCloseLogicalChannel((Integer) request.argument, onCompleted);
505                    }
506                    break;
507
508                case EVENT_CLOSE_CHANNEL_DONE:
509                    handleNullReturnEvent(msg, "iccCloseLogicalChannel");
510                    break;
511
512                case CMD_NV_READ_ITEM:
513                    request = (MainThreadRequest) msg.obj;
514                    onCompleted = obtainMessage(EVENT_NV_READ_ITEM_DONE, request);
515                    mPhone.nvReadItem((Integer) request.argument, onCompleted);
516                    break;
517
518                case EVENT_NV_READ_ITEM_DONE:
519                    ar = (AsyncResult) msg.obj;
520                    request = (MainThreadRequest) ar.userObj;
521                    if (ar.exception == null && ar.result != null) {
522                        request.result = ar.result;     // String
523                    } else {
524                        request.result = "";
525                        if (ar.result == null) {
526                            loge("nvReadItem: Empty response");
527                        } else if (ar.exception instanceof CommandException) {
528                            loge("nvReadItem: CommandException: " +
529                                    ar.exception);
530                        } else {
531                            loge("nvReadItem: Unknown exception");
532                        }
533                    }
534                    synchronized (request) {
535                        request.notifyAll();
536                    }
537                    break;
538
539                case CMD_NV_WRITE_ITEM:
540                    request = (MainThreadRequest) msg.obj;
541                    onCompleted = obtainMessage(EVENT_NV_WRITE_ITEM_DONE, request);
542                    Pair<Integer, String> idValue = (Pair<Integer, String>) request.argument;
543                    mPhone.nvWriteItem(idValue.first, idValue.second, onCompleted);
544                    break;
545
546                case EVENT_NV_WRITE_ITEM_DONE:
547                    handleNullReturnEvent(msg, "nvWriteItem");
548                    break;
549
550                case CMD_NV_WRITE_CDMA_PRL:
551                    request = (MainThreadRequest) msg.obj;
552                    onCompleted = obtainMessage(EVENT_NV_WRITE_CDMA_PRL_DONE, request);
553                    mPhone.nvWriteCdmaPrl((byte[]) request.argument, onCompleted);
554                    break;
555
556                case EVENT_NV_WRITE_CDMA_PRL_DONE:
557                    handleNullReturnEvent(msg, "nvWriteCdmaPrl");
558                    break;
559
560                case CMD_NV_RESET_CONFIG:
561                    request = (MainThreadRequest) msg.obj;
562                    onCompleted = obtainMessage(EVENT_NV_RESET_CONFIG_DONE, request);
563                    mPhone.nvResetConfig((Integer) request.argument, onCompleted);
564                    break;
565
566                case EVENT_NV_RESET_CONFIG_DONE:
567                    handleNullReturnEvent(msg, "nvResetConfig");
568                    break;
569
570                case CMD_GET_PREFERRED_NETWORK_TYPE:
571                    request = (MainThreadRequest) msg.obj;
572                    onCompleted = obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE_DONE, request);
573                    getPhoneFromRequest(request).getPreferredNetworkType(onCompleted);
574                    break;
575
576                case EVENT_GET_PREFERRED_NETWORK_TYPE_DONE:
577                    ar = (AsyncResult) msg.obj;
578                    request = (MainThreadRequest) ar.userObj;
579                    if (ar.exception == null && ar.result != null) {
580                        request.result = ar.result;     // Integer
581                    } else {
582                        request.result = -1;
583                        if (ar.result == null) {
584                            loge("getPreferredNetworkType: Empty response");
585                        } else if (ar.exception instanceof CommandException) {
586                            loge("getPreferredNetworkType: CommandException: " +
587                                    ar.exception);
588                        } else {
589                            loge("getPreferredNetworkType: Unknown exception");
590                        }
591                    }
592                    synchronized (request) {
593                        request.notifyAll();
594                    }
595                    break;
596
597                case CMD_SET_PREFERRED_NETWORK_TYPE:
598                    request = (MainThreadRequest) msg.obj;
599                    onCompleted = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE_DONE, request);
600                    int networkType = (Integer) request.argument;
601                    getPhoneFromRequest(request).setPreferredNetworkType(networkType, onCompleted);
602                    break;
603
604                case EVENT_SET_PREFERRED_NETWORK_TYPE_DONE:
605                    handleNullReturnEvent(msg, "setPreferredNetworkType");
606                    break;
607
608                case CMD_INVOKE_OEM_RIL_REQUEST_RAW:
609                    request = (MainThreadRequest)msg.obj;
610                    onCompleted = obtainMessage(EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE, request);
611                    mPhone.invokeOemRilRequestRaw((byte[])request.argument, onCompleted);
612                    break;
613
614                case EVENT_INVOKE_OEM_RIL_REQUEST_RAW_DONE:
615                    ar = (AsyncResult)msg.obj;
616                    request = (MainThreadRequest)ar.userObj;
617                    request.result = ar;
618                    synchronized (request) {
619                        request.notifyAll();
620                    }
621                    break;
622
623                case CMD_SET_VOICEMAIL_NUMBER:
624                    request = (MainThreadRequest) msg.obj;
625                    onCompleted = obtainMessage(EVENT_SET_VOICEMAIL_NUMBER_DONE, request);
626                    Pair<String, String> tagNum = (Pair<String, String>) request.argument;
627                    getPhoneFromRequest(request).setVoiceMailNumber(tagNum.first, tagNum.second,
628                            onCompleted);
629                    break;
630
631                case EVENT_SET_VOICEMAIL_NUMBER_DONE:
632                    handleNullReturnEvent(msg, "setVoicemailNumber");
633                    break;
634
635                case CMD_SET_NETWORK_SELECTION_MODE_AUTOMATIC:
636                    request = (MainThreadRequest) msg.obj;
637                    onCompleted = obtainMessage(EVENT_SET_NETWORK_SELECTION_MODE_AUTOMATIC_DONE,
638                            request);
639                    getPhoneFromRequest(request).setNetworkSelectionModeAutomatic(onCompleted);
640                    break;
641
642                case EVENT_SET_NETWORK_SELECTION_MODE_AUTOMATIC_DONE:
643                    handleNullReturnEvent(msg, "setNetworkSelectionModeAutomatic");
644                    break;
645
646                default:
647                    Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
648                    break;
649            }
650        }
651
652        private void handleNullReturnEvent(Message msg, String command) {
653            AsyncResult ar = (AsyncResult) msg.obj;
654            MainThreadRequest request = (MainThreadRequest) ar.userObj;
655            if (ar.exception == null) {
656                request.result = true;
657            } else {
658                request.result = false;
659                if (ar.exception instanceof CommandException) {
660                    loge(command + ": CommandException: " + ar.exception);
661                } else {
662                    loge(command + ": Unknown exception");
663                }
664            }
665            synchronized (request) {
666                request.notifyAll();
667            }
668        }
669    }
670
671    /**
672     * Posts the specified command to be executed on the main thread,
673     * waits for the request to complete, and returns the result.
674     * @see #sendRequestAsync
675     */
676    private Object sendRequest(int command, Object argument) {
677        return sendRequest(command, argument, null);
678    }
679
680    /**
681     * Posts the specified command to be executed on the main thread,
682     * waits for the request to complete, and returns the result.
683     * @see #sendRequestAsync
684     */
685    private Object sendRequest(int command, Object argument, Integer subId) {
686        if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
687            throw new RuntimeException("This method will deadlock if called from the main thread.");
688        }
689
690        MainThreadRequest request = new MainThreadRequest(argument, subId);
691        Message msg = mMainThreadHandler.obtainMessage(command, request);
692        msg.sendToTarget();
693
694        // Wait for the request to complete
695        synchronized (request) {
696            while (request.result == null) {
697                try {
698                    request.wait();
699                } catch (InterruptedException e) {
700                    // Do nothing, go back and wait until the request is complete
701                }
702            }
703        }
704        return request.result;
705    }
706
707    /**
708     * Asynchronous ("fire and forget") version of sendRequest():
709     * Posts the specified command to be executed on the main thread, and
710     * returns immediately.
711     * @see #sendRequest
712     */
713    private void sendRequestAsync(int command) {
714        mMainThreadHandler.sendEmptyMessage(command);
715    }
716
717    /**
718     * Same as {@link #sendRequestAsync(int)} except it takes an argument.
719     * @see {@link #sendRequest(int,Object)}
720     */
721    private void sendRequestAsync(int command, Object argument) {
722        MainThreadRequest request = new MainThreadRequest(argument);
723        Message msg = mMainThreadHandler.obtainMessage(command, request);
724        msg.sendToTarget();
725    }
726
727    /**
728     * Initialize the singleton PhoneInterfaceManager instance.
729     * This is only done once, at startup, from PhoneApp.onCreate().
730     */
731    /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) {
732        synchronized (PhoneInterfaceManager.class) {
733            if (sInstance == null) {
734                sInstance = new PhoneInterfaceManager(app, phone);
735            } else {
736                Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
737            }
738            return sInstance;
739        }
740    }
741
742    /** Private constructor; @see init() */
743    private PhoneInterfaceManager(PhoneGlobals app, Phone phone) {
744        mApp = app;
745        mPhone = phone;
746        mCM = PhoneGlobals.getInstance().mCM;
747        mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE);
748        mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
749        mMainThreadHandler = new MainThreadHandler();
750        mTelephonySharedPreferences =
751                PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
752        mSubscriptionController = SubscriptionController.getInstance();
753
754        publish();
755    }
756
757    private void publish() {
758        if (DBG) log("publish: " + this);
759
760        ServiceManager.addService("phone", this);
761    }
762
763    private Phone getPhoneFromRequest(MainThreadRequest request) {
764        return (request.subId == null) ? mPhone : getPhone(request.subId);
765    }
766
767    // returns phone associated with the subId.
768    private Phone getPhone(int subId) {
769        return PhoneFactory.getPhone(mSubscriptionController.getPhoneId(subId));
770    }
771    //
772    // Implementation of the ITelephony interface.
773    //
774
775    public void dial(String number) {
776        dialForSubscriber(getPreferredVoiceSubscription(), number);
777    }
778
779    public void dialForSubscriber(int subId, String number) {
780        if (DBG) log("dial: " + number);
781        // No permission check needed here: This is just a wrapper around the
782        // ACTION_DIAL intent, which is available to any app since it puts up
783        // the UI before it does anything.
784
785        String url = createTelUrl(number);
786        if (url == null) {
787            return;
788        }
789
790        // PENDING: should we just silently fail if phone is offhook or ringing?
791        PhoneConstants.State state = mCM.getState(subId);
792        if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
793            Intent  intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
794            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
795            mApp.startActivity(intent);
796        }
797    }
798
799    public void call(String callingPackage, String number) {
800        callForSubscriber(getPreferredVoiceSubscription(), callingPackage, number);
801    }
802
803    public void callForSubscriber(int subId, String callingPackage, String number) {
804        if (DBG) log("call: " + number);
805
806        // This is just a wrapper around the ACTION_CALL intent, but we still
807        // need to do a permission check since we're calling startActivity()
808        // from the context of the phone app.
809        enforceCallPermission();
810
811        if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
812                != AppOpsManager.MODE_ALLOWED) {
813            return;
814        }
815
816        String url = createTelUrl(number);
817        if (url == null) {
818            return;
819        }
820
821        boolean isValid = false;
822        final List<SubscriptionInfo> slist = getActiveSubscriptionInfoList();
823        if (slist != null) {
824            for (SubscriptionInfo subInfoRecord : slist) {
825                if (subInfoRecord.getSubscriptionId() == subId) {
826                    isValid = true;
827                    break;
828                }
829            }
830        }
831        if (isValid == false) {
832            return;
833        }
834
835        Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
836        intent.putExtra(SUBSCRIPTION_KEY, subId);
837        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
838        mApp.startActivity(intent);
839    }
840
841    /**
842     * End a call based on call state
843     * @return true is a call was ended
844     */
845    public boolean endCall() {
846        return endCallForSubscriber(getDefaultSubscription());
847    }
848
849    /**
850     * End a call based on the call state of the subId
851     * @return true is a call was ended
852     */
853    public boolean endCallForSubscriber(int subId) {
854        enforceCallPermission();
855        return (Boolean) sendRequest(CMD_END_CALL, null, new Integer(subId));
856    }
857
858    public void answerRingingCall() {
859        answerRingingCallForSubscriber(getDefaultSubscription());
860    }
861
862    public void answerRingingCallForSubscriber(int subId) {
863        if (DBG) log("answerRingingCall...");
864        // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
865        // but that can probably wait till the big TelephonyManager API overhaul.
866        // For now, protect this call with the MODIFY_PHONE_STATE permission.
867        enforceModifyPermission();
868        sendRequest(CMD_ANSWER_RINGING_CALL, null, new Integer(subId));
869    }
870
871    /**
872     * Make the actual telephony calls to implement answerRingingCall().
873     * This should only be called from the main thread of the Phone app.
874     * @see #answerRingingCall
875     *
876     * TODO: it would be nice to return true if we answered the call, or
877     * false if there wasn't actually a ringing incoming call, or some
878     * other error occurred.  (In other words, pass back the return value
879     * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
880     * But that would require calling this method via sendRequest() rather
881     * than sendRequestAsync(), and right now we don't actually *need* that
882     * return value, so let's just return void for now.
883     */
884    private void answerRingingCallInternal(int subId) {
885        final boolean hasRingingCall = !getPhone(subId).getRingingCall().isIdle();
886        if (hasRingingCall) {
887            final boolean hasActiveCall = !getPhone(subId).getForegroundCall().isIdle();
888            final boolean hasHoldingCall = !getPhone(subId).getBackgroundCall().isIdle();
889            if (hasActiveCall && hasHoldingCall) {
890                // Both lines are in use!
891                // TODO: provide a flag to let the caller specify what
892                // policy to use if both lines are in use.  (The current
893                // behavior is hardwired to "answer incoming, end ongoing",
894                // which is how the CALL button is specced to behave.)
895                PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
896                return;
897            } else {
898                // answerCall() will automatically hold the current active
899                // call, if there is one.
900                PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
901                return;
902            }
903        } else {
904            // No call was ringing.
905            return;
906        }
907    }
908
909    /**
910     * This method is no longer used and can be removed once TelephonyManager stops referring to it.
911     */
912    public void silenceRinger() {
913        Log.e(LOG_TAG, "silenseRinger not supported");
914    }
915
916    public boolean isOffhook() {
917        return isOffhookForSubscriber(getDefaultSubscription());
918    }
919
920    public boolean isOffhookForSubscriber(int subId) {
921        return (getPhone(subId).getState() == PhoneConstants.State.OFFHOOK);
922    }
923
924    public boolean isRinging() {
925        return (isRingingForSubscriber(getDefaultSubscription()));
926    }
927
928    public boolean isRingingForSubscriber(int subId) {
929        return (getPhone(subId).getState() == PhoneConstants.State.RINGING);
930    }
931
932    public boolean isIdle() {
933        return isIdleForSubscriber(getDefaultSubscription());
934    }
935
936    public boolean isIdleForSubscriber(int subId) {
937        return (getPhone(subId).getState() == PhoneConstants.State.IDLE);
938    }
939
940    public boolean isSimPinEnabled(String callingPackage) {
941        if (!canReadPhoneState(callingPackage, "isSimPinEnabled")) {
942            return false;
943        }
944
945        return (PhoneGlobals.getInstance().isSimPinEnabled());
946    }
947
948    public boolean supplyPin(String pin) {
949        return supplyPinForSubscriber(getDefaultSubscription(), pin);
950    }
951
952    public boolean supplyPinForSubscriber(int subId, String pin) {
953        int [] resultArray = supplyPinReportResultForSubscriber(subId, pin);
954        return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
955    }
956
957    public boolean supplyPuk(String puk, String pin) {
958        return supplyPukForSubscriber(getDefaultSubscription(), puk, pin);
959    }
960
961    public boolean supplyPukForSubscriber(int subId, String puk, String pin) {
962        int [] resultArray = supplyPukReportResultForSubscriber(subId, puk, pin);
963        return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
964    }
965
966    /** {@hide} */
967    public int[] supplyPinReportResult(String pin) {
968        return supplyPinReportResultForSubscriber(getDefaultSubscription(), pin);
969    }
970
971    public int[] supplyPinReportResultForSubscriber(int subId, String pin) {
972        enforceModifyPermission();
973        final UnlockSim checkSimPin = new UnlockSim(getPhone(subId).getIccCard());
974        checkSimPin.start();
975        return checkSimPin.unlockSim(null, pin);
976    }
977
978    /** {@hide} */
979    public int[] supplyPukReportResult(String puk, String pin) {
980        return supplyPukReportResultForSubscriber(getDefaultSubscription(), puk, pin);
981    }
982
983    public int[] supplyPukReportResultForSubscriber(int subId, String puk, String pin) {
984        enforceModifyPermission();
985        final UnlockSim checkSimPuk = new UnlockSim(getPhone(subId).getIccCard());
986        checkSimPuk.start();
987        return checkSimPuk.unlockSim(puk, pin);
988    }
989
990    /**
991     * Helper thread to turn async call to SimCard#supplyPin into
992     * a synchronous one.
993     */
994    private static class UnlockSim extends Thread {
995
996        private final IccCard mSimCard;
997
998        private boolean mDone = false;
999        private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
1000        private int mRetryCount = -1;
1001
1002        // For replies from SimCard interface
1003        private Handler mHandler;
1004
1005        // For async handler to identify request type
1006        private static final int SUPPLY_PIN_COMPLETE = 100;
1007
1008        public UnlockSim(IccCard simCard) {
1009            mSimCard = simCard;
1010        }
1011
1012        @Override
1013        public void run() {
1014            Looper.prepare();
1015            synchronized (UnlockSim.this) {
1016                mHandler = new Handler() {
1017                    @Override
1018                    public void handleMessage(Message msg) {
1019                        AsyncResult ar = (AsyncResult) msg.obj;
1020                        switch (msg.what) {
1021                            case SUPPLY_PIN_COMPLETE:
1022                                Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
1023                                synchronized (UnlockSim.this) {
1024                                    mRetryCount = msg.arg1;
1025                                    if (ar.exception != null) {
1026                                        if (ar.exception instanceof CommandException &&
1027                                                ((CommandException)(ar.exception)).getCommandError()
1028                                                == CommandException.Error.PASSWORD_INCORRECT) {
1029                                            mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
1030                                        } else {
1031                                            mResult = PhoneConstants.PIN_GENERAL_FAILURE;
1032                                        }
1033                                    } else {
1034                                        mResult = PhoneConstants.PIN_RESULT_SUCCESS;
1035                                    }
1036                                    mDone = true;
1037                                    UnlockSim.this.notifyAll();
1038                                }
1039                                break;
1040                        }
1041                    }
1042                };
1043                UnlockSim.this.notifyAll();
1044            }
1045            Looper.loop();
1046        }
1047
1048        /*
1049         * Use PIN or PUK to unlock SIM card
1050         *
1051         * If PUK is null, unlock SIM card with PIN
1052         *
1053         * If PUK is not null, unlock SIM card with PUK and set PIN code
1054         */
1055        synchronized int[] unlockSim(String puk, String pin) {
1056
1057            while (mHandler == null) {
1058                try {
1059                    wait();
1060                } catch (InterruptedException e) {
1061                    Thread.currentThread().interrupt();
1062                }
1063            }
1064            Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
1065
1066            if (puk == null) {
1067                mSimCard.supplyPin(pin, callback);
1068            } else {
1069                mSimCard.supplyPuk(puk, pin, callback);
1070            }
1071
1072            while (!mDone) {
1073                try {
1074                    Log.d(LOG_TAG, "wait for done");
1075                    wait();
1076                } catch (InterruptedException e) {
1077                    // Restore the interrupted status
1078                    Thread.currentThread().interrupt();
1079                }
1080            }
1081            Log.d(LOG_TAG, "done");
1082            int[] resultArray = new int[2];
1083            resultArray[0] = mResult;
1084            resultArray[1] = mRetryCount;
1085            return resultArray;
1086        }
1087    }
1088
1089    public void updateServiceLocation() {
1090        updateServiceLocationForSubscriber(getDefaultSubscription());
1091
1092    }
1093
1094    public void updateServiceLocationForSubscriber(int subId) {
1095        // No permission check needed here: this call is harmless, and it's
1096        // needed for the ServiceState.requestStateUpdate() call (which is
1097        // already intentionally exposed to 3rd parties.)
1098        getPhone(subId).updateServiceLocation();
1099    }
1100
1101    public boolean isRadioOn() {
1102        return isRadioOnForSubscriber(getDefaultSubscription());
1103    }
1104
1105    public boolean isRadioOnForSubscriber(int subId) {
1106        return getPhone(subId).getServiceState().getState() != ServiceState.STATE_POWER_OFF;
1107    }
1108
1109    public void toggleRadioOnOff() {
1110        toggleRadioOnOffForSubscriber(getDefaultSubscription());
1111
1112    }
1113
1114    public void toggleRadioOnOffForSubscriber(int subId) {
1115        enforceModifyPermission();
1116        getPhone(subId).setRadioPower(!isRadioOnForSubscriber(subId));
1117    }
1118
1119    public boolean setRadio(boolean turnOn) {
1120        return setRadioForSubscriber(getDefaultSubscription(), turnOn);
1121    }
1122
1123    public boolean setRadioForSubscriber(int subId, boolean turnOn) {
1124        enforceModifyPermission();
1125        if ((getPhone(subId).getServiceState().getState() !=
1126                ServiceState.STATE_POWER_OFF) != turnOn) {
1127            toggleRadioOnOffForSubscriber(subId);
1128        }
1129        return true;
1130    }
1131
1132    public boolean needMobileRadioShutdown() {
1133        /*
1134         * If any of the Radios are available, it will need to be
1135         * shutdown. So return true if any Radio is available.
1136         */
1137        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
1138            Phone phone = PhoneFactory.getPhone(i);
1139            if (phone != null && phone.isRadioAvailable()) return true;
1140        }
1141        logv(TelephonyManager.getDefault().getPhoneCount() + " Phones are shutdown.");
1142        return false;
1143    }
1144
1145    public void shutdownMobileRadios() {
1146        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
1147            logv("Shutting down Phone " + i);
1148            shutdownRadioUsingPhoneId(i);
1149        }
1150    }
1151
1152    private void shutdownRadioUsingPhoneId(int phoneId) {
1153        enforceModifyPermission();
1154        Phone phone = PhoneFactory.getPhone(phoneId);
1155        if (phone != null && phone.isRadioAvailable()) {
1156            phone.shutdownRadio();
1157        }
1158    }
1159
1160    public boolean setRadioPower(boolean turnOn) {
1161        return setRadioPowerForSubscriber(getDefaultSubscription(), turnOn);
1162    }
1163
1164    public boolean setRadioPowerForSubscriber(int subId, boolean turnOn) {
1165        enforceModifyPermission();
1166        getPhone(subId).setRadioPower(turnOn);
1167        return true;
1168    }
1169
1170    // FIXME: subId version needed
1171    public boolean enableDataConnectivity() {
1172        enforceModifyPermission();
1173        int subId = mSubscriptionController.getDefaultDataSubId();
1174        getPhone(subId).setDataEnabled(true);
1175        return true;
1176    }
1177
1178    // FIXME: subId version needed
1179    public boolean disableDataConnectivity() {
1180        enforceModifyPermission();
1181        int subId = mSubscriptionController.getDefaultDataSubId();
1182        getPhone(subId).setDataEnabled(false);
1183        return true;
1184    }
1185
1186    // FIXME: subId version needed
1187    public boolean isDataConnectivityPossible() {
1188        int subId = mSubscriptionController.getDefaultDataSubId();
1189        return getPhone(subId).isDataConnectivityPossible();
1190    }
1191
1192    public boolean handlePinMmi(String dialString) {
1193        return handlePinMmiForSubscriber(getDefaultSubscription(), dialString);
1194    }
1195
1196    public boolean handlePinMmiForSubscriber(int subId, String dialString) {
1197        enforceModifyPermission();
1198        return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString, subId);
1199    }
1200
1201    public int getCallState() {
1202        return getCallStateForSubscriber(getDefaultSubscription());
1203    }
1204
1205    public int getCallStateForSubscriber(int subId) {
1206        return DefaultPhoneNotifier.convertCallState(getPhone(subId).getState());
1207    }
1208
1209    public int getDataState() {
1210        Phone phone = getPhone(mSubscriptionController.getDefaultDataSubId());
1211        return DefaultPhoneNotifier.convertDataState(phone.getDataConnectionState());
1212    }
1213
1214    public int getDataActivity() {
1215        Phone phone = getPhone(mSubscriptionController.getDefaultDataSubId());
1216        return DefaultPhoneNotifier.convertDataActivityState(phone.getDataActivityState());
1217    }
1218
1219    @Override
1220    public Bundle getCellLocation(String callingPackage) {
1221        enforceFineOrCoarseLocationPermission("getCellLocation");
1222
1223        // OP_COARSE_LOCATION controls both fine and coarse location.
1224        if (mAppOps.noteOp(AppOpsManager.OP_COARSE_LOCATION, Binder.getCallingUid(),
1225                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1226            log("getCellLocation: returning null; mode != allowed");
1227            return null;
1228        }
1229
1230        if (checkIfCallerIsSelfOrForegroundUser()) {
1231            if (DBG_LOC) log("getCellLocation: is active user");
1232            Bundle data = new Bundle();
1233            Phone phone = getPhone(mSubscriptionController.getDefaultDataSubId());
1234            phone.getCellLocation().fillInNotifierBundle(data);
1235            return data;
1236        } else {
1237            log("getCellLocation: suppress non-active user");
1238            return null;
1239        }
1240    }
1241
1242    private void enforceFineOrCoarseLocationPermission(String message) {
1243        try {
1244            mApp.enforceCallingOrSelfPermission(
1245                    android.Manifest.permission.ACCESS_FINE_LOCATION, null);
1246        } catch (SecurityException e) {
1247            // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
1248            // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
1249            // is the weaker precondition
1250            mApp.enforceCallingOrSelfPermission(
1251                    android.Manifest.permission.ACCESS_COARSE_LOCATION, message);
1252        }
1253    }
1254
1255
1256    @Override
1257    public void enableLocationUpdates() {
1258        enableLocationUpdatesForSubscriber(getDefaultSubscription());
1259    }
1260
1261    public void enableLocationUpdatesForSubscriber(int subId) {
1262        mApp.enforceCallingOrSelfPermission(
1263                android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
1264        getPhone(subId).enableLocationUpdates();
1265    }
1266
1267    @Override
1268    public void disableLocationUpdates() {
1269        disableLocationUpdatesForSubscriber(getDefaultSubscription());
1270    }
1271
1272    public void disableLocationUpdatesForSubscriber(int subId) {
1273        mApp.enforceCallingOrSelfPermission(
1274                android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
1275        getPhone(subId).disableLocationUpdates();
1276    }
1277
1278    @Override
1279    @SuppressWarnings("unchecked")
1280    public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
1281        enforceFineOrCoarseLocationPermission("getNeighboringCellInfo");
1282
1283        // OP_COARSE_LOCATION controls both fine and coarse location.
1284        if (mAppOps.noteOp(AppOpsManager.OP_COARSE_LOCATION, Binder.getCallingUid(),
1285                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1286            return null;
1287        }
1288
1289        if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
1290                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1291            return null;
1292        }
1293
1294        if (checkIfCallerIsSelfOrForegroundUser()) {
1295            if (DBG_LOC) log("getNeighboringCellInfo: is active user");
1296
1297            ArrayList<NeighboringCellInfo> cells = null;
1298
1299            try {
1300                cells = (ArrayList<NeighboringCellInfo>) sendRequest(
1301                        CMD_HANDLE_NEIGHBORING_CELL, null, null);
1302            } catch (RuntimeException e) {
1303                Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
1304            }
1305            return cells;
1306        } else {
1307            if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
1308            return null;
1309        }
1310    }
1311
1312
1313    @Override
1314    public List<CellInfo> getAllCellInfo(String callingPackage) {
1315        enforceFineOrCoarseLocationPermission("getAllCellInfo");
1316
1317        // OP_COARSE_LOCATION controls both fine and coarse location.
1318        if (mAppOps.noteOp(AppOpsManager.OP_COARSE_LOCATION, Binder.getCallingUid(),
1319                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1320            return null;
1321        }
1322
1323        if (checkIfCallerIsSelfOrForegroundUser()) {
1324            if (DBG_LOC) log("getAllCellInfo: is active user");
1325            List<CellInfo> cellInfos = new ArrayList<CellInfo>();
1326            for (Phone phone : PhoneFactory.getPhones()) {
1327                cellInfos.addAll(phone.getAllCellInfo());
1328            }
1329            return cellInfos;
1330        } else {
1331            if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
1332            return null;
1333        }
1334    }
1335
1336    @Override
1337    public void setCellInfoListRate(int rateInMillis) {
1338        mPhone.setCellInfoListRate(rateInMillis);
1339    }
1340
1341    //
1342    // Internal helper methods.
1343    //
1344
1345    private static boolean checkIfCallerIsSelfOrForegroundUser() {
1346        boolean ok;
1347
1348        boolean self = Binder.getCallingUid() == Process.myUid();
1349        if (!self) {
1350            // Get the caller's user id then clear the calling identity
1351            // which will be restored in the finally clause.
1352            int callingUser = UserHandle.getCallingUserId();
1353            long ident = Binder.clearCallingIdentity();
1354
1355            try {
1356                // With calling identity cleared the current user is the foreground user.
1357                int foregroundUser = ActivityManager.getCurrentUser();
1358                ok = (foregroundUser == callingUser);
1359                if (DBG_LOC) {
1360                    log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
1361                            + " callingUser=" + callingUser + " ok=" + ok);
1362                }
1363            } catch (Exception ex) {
1364                if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
1365                ok = false;
1366            } finally {
1367                Binder.restoreCallingIdentity(ident);
1368            }
1369        } else {
1370            if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
1371            ok = true;
1372        }
1373        if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
1374        return ok;
1375    }
1376
1377    /**
1378     * Make sure the caller has the MODIFY_PHONE_STATE permission.
1379     *
1380     * @throws SecurityException if the caller does not have the required permission
1381     */
1382    private void enforceModifyPermission() {
1383        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
1384    }
1385
1386    /**
1387     * Make sure either system app or the caller has carrier privilege.
1388     *
1389     * @throws SecurityException if the caller does not have the required permission/privilege
1390     */
1391    private void enforceModifyPermissionOrCarrierPrivilege() {
1392        int permission = mApp.checkCallingOrSelfPermission(
1393                android.Manifest.permission.MODIFY_PHONE_STATE);
1394        if (permission == PackageManager.PERMISSION_GRANTED) {
1395            return;
1396        }
1397
1398        log("No modify permission, check carrier privilege next.");
1399        if (getCarrierPrivilegeStatus() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1400            loge("No Carrier Privilege.");
1401            throw new SecurityException("No modify permission or carrier privilege.");
1402        }
1403    }
1404
1405    /**
1406     * Make sure the caller has carrier privilege.
1407     *
1408     * @throws SecurityException if the caller does not have the required permission
1409     */
1410    private void enforceCarrierPrivilege() {
1411        if (getCarrierPrivilegeStatus() != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
1412            loge("No Carrier Privilege.");
1413            throw new SecurityException("No Carrier Privilege.");
1414        }
1415    }
1416
1417    /**
1418     * Make sure the caller has the CALL_PHONE permission.
1419     *
1420     * @throws SecurityException if the caller does not have the required permission
1421     */
1422    private void enforceCallPermission() {
1423        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
1424    }
1425
1426    /**
1427     * Make sure the caller has the READ_PRIVILEGED_PHONE_STATE permission.
1428     *
1429     * @throws SecurityException if the caller does not have the required permission
1430     */
1431    private void enforcePrivilegedPhoneStatePermission() {
1432        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1433                null);
1434    }
1435
1436    private void enforceConnectivityInternalPermission() {
1437        mApp.enforceCallingOrSelfPermission(
1438                android.Manifest.permission.CONNECTIVITY_INTERNAL,
1439                "ConnectivityService");
1440    }
1441
1442    private String createTelUrl(String number) {
1443        if (TextUtils.isEmpty(number)) {
1444            return null;
1445        }
1446
1447        return "tel:" + number;
1448    }
1449
1450    private static void log(String msg) {
1451        Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
1452    }
1453
1454    private static void logv(String msg) {
1455        Log.v(LOG_TAG, "[PhoneIntfMgr] " + msg);
1456    }
1457
1458    private static void loge(String msg) {
1459        Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
1460    }
1461
1462    public int getActivePhoneType() {
1463        return getActivePhoneTypeForSubscriber(getDefaultSubscription());
1464    }
1465
1466    public int getActivePhoneTypeForSubscriber(int subId) {
1467        return getPhone(subId).getPhoneType();
1468    }
1469
1470    /**
1471     * Returns the CDMA ERI icon index to display
1472     */
1473    public int getCdmaEriIconIndex() {
1474        return getCdmaEriIconIndexForSubscriber(getDefaultSubscription());
1475
1476    }
1477
1478    public int getCdmaEriIconIndexForSubscriber(int subId) {
1479        return getPhone(subId).getCdmaEriIconIndex();
1480    }
1481
1482    /**
1483     * Returns the CDMA ERI icon mode,
1484     * 0 - ON
1485     * 1 - FLASHING
1486     */
1487    public int getCdmaEriIconMode() {
1488        return getCdmaEriIconModeForSubscriber(getDefaultSubscription());
1489    }
1490
1491    public int getCdmaEriIconModeForSubscriber(int subId) {
1492        return getPhone(subId).getCdmaEriIconMode();
1493    }
1494
1495    /**
1496     * Returns the CDMA ERI text,
1497     */
1498    public String getCdmaEriText() {
1499        return getCdmaEriTextForSubscriber(getDefaultSubscription());
1500    }
1501
1502    public String getCdmaEriTextForSubscriber(int subId) {
1503        return getPhone(subId).getCdmaEriText();
1504    }
1505
1506    /**
1507     * Returns the CDMA MDN.
1508     */
1509    public String getCdmaMdn(int subId) {
1510        enforceModifyPermissionOrCarrierPrivilege();
1511        if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
1512            return getPhone(subId).getLine1Number();
1513        } else {
1514            return null;
1515        }
1516    }
1517
1518    /**
1519     * Returns the CDMA MIN.
1520     */
1521    public String getCdmaMin(int subId) {
1522        enforceModifyPermissionOrCarrierPrivilege();
1523        if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
1524            return getPhone(subId).getCdmaMin();
1525        } else {
1526            return null;
1527        }
1528    }
1529
1530    /**
1531     * Returns true if CDMA provisioning needs to run.
1532     */
1533    public boolean needsOtaServiceProvisioning() {
1534        return mPhone.needsOtaServiceProvisioning();
1535    }
1536
1537    /**
1538     * Sets the voice mail number of a given subId.
1539     */
1540    @Override
1541    public boolean setVoiceMailNumber(int subId, String alphaTag, String number) {
1542        enforceCarrierPrivilege();
1543        Boolean success = (Boolean) sendRequest(CMD_SET_VOICEMAIL_NUMBER,
1544                new Pair<String, String>(alphaTag, number), new Integer(subId));
1545        return success;
1546    }
1547
1548    /**
1549     * Returns the unread count of voicemails
1550     */
1551    public int getVoiceMessageCount() {
1552        return getVoiceMessageCountForSubscriber(getDefaultSubscription());
1553    }
1554
1555    /**
1556     * Returns the unread count of voicemails for a subId
1557     */
1558    public int getVoiceMessageCountForSubscriber( int subId) {
1559        return getPhone(subId).getVoiceMessageCount();
1560    }
1561
1562    /**
1563     * Returns the data network type
1564     *
1565     * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
1566     */
1567    @Override
1568    public int getNetworkType() {
1569        return getNetworkTypeForSubscriber(getDefaultSubscription());
1570    }
1571
1572    /**
1573     * Returns the network type for a subId
1574     */
1575    @Override
1576    public int getNetworkTypeForSubscriber(int subId) {
1577        return getPhone(subId).getServiceState().getDataNetworkType();
1578    }
1579
1580    /**
1581     * Returns the data network type
1582     */
1583    @Override
1584    public int getDataNetworkType() {
1585        return getDataNetworkTypeForSubscriber(getDefaultSubscription());
1586    }
1587
1588    /**
1589     * Returns the data network type for a subId
1590     */
1591    @Override
1592    public int getDataNetworkTypeForSubscriber(int subId) {
1593        return getPhone(subId).getServiceState().getDataNetworkType();
1594    }
1595
1596    /**
1597     * Returns the data network type
1598     */
1599    @Override
1600    public int getVoiceNetworkType() {
1601        return getVoiceNetworkTypeForSubscriber(getDefaultSubscription());
1602    }
1603
1604    /**
1605     * Returns the Voice network type for a subId
1606     */
1607    @Override
1608    public int getVoiceNetworkTypeForSubscriber(int subId) {
1609        return getPhone(subId).getServiceState().getVoiceNetworkType();
1610    }
1611
1612    /**
1613     * @return true if a ICC card is present
1614     */
1615    public boolean hasIccCard() {
1616        // FIXME Make changes to pass defaultSimId of type int
1617        return hasIccCardUsingSlotId(mSubscriptionController.getSlotId(getDefaultSubscription()));
1618    }
1619
1620    /**
1621     * @return true if a ICC card is present for a slotId
1622     */
1623    public boolean hasIccCardUsingSlotId(int slotId) {
1624        int subId[] = mSubscriptionController.getSubIdUsingSlotId(slotId);
1625        if (subId != null) {
1626            return getPhone(subId[0]).getIccCard().hasIccCard();
1627        } else {
1628            return false;
1629        }
1630    }
1631
1632    /**
1633     * Return if the current radio is LTE on CDMA. This
1634     * is a tri-state return value as for a period of time
1635     * the mode may be unknown.
1636     *
1637     * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
1638     * or {@link Phone#LTE_ON_CDMA_TRUE}
1639     */
1640    public int getLteOnCdmaMode() {
1641        return getLteOnCdmaModeForSubscriber(getDefaultSubscription());
1642    }
1643
1644    public int getLteOnCdmaModeForSubscriber(int subId) {
1645        return getPhone(subId).getLteOnCdmaMode();
1646    }
1647
1648    public void setPhone(Phone phone) {
1649        mPhone = phone;
1650    }
1651
1652    /**
1653     * {@hide}
1654     * Returns Default subId, 0 in the case of single standby.
1655     */
1656    private int getDefaultSubscription() {
1657        return mSubscriptionController.getDefaultSubId();
1658    }
1659
1660    private int getPreferredVoiceSubscription() {
1661        return mSubscriptionController.getDefaultVoiceSubId();
1662    }
1663
1664    /**
1665     * @see android.telephony.TelephonyManager.WifiCallingChoices
1666     */
1667    public int getWhenToMakeWifiCalls() {
1668        return Settings.System.getInt(mPhone.getContext().getContentResolver(),
1669                Settings.System.WHEN_TO_MAKE_WIFI_CALLS, getWhenToMakeWifiCallsDefaultPreference());
1670    }
1671
1672    /**
1673     * @see android.telephony.TelephonyManager.WifiCallingChoices
1674     */
1675    public void setWhenToMakeWifiCalls(int preference) {
1676        if (DBG) log("setWhenToMakeWifiCallsStr, storing setting = " + preference);
1677        Settings.System.putInt(mPhone.getContext().getContentResolver(),
1678                Settings.System.WHEN_TO_MAKE_WIFI_CALLS, preference);
1679    }
1680
1681    private static int getWhenToMakeWifiCallsDefaultPreference() {
1682        // TODO: Use a build property to choose this value.
1683        return TelephonyManager.WifiCallingChoices.ALWAYS_USE;
1684    }
1685
1686    @Override
1687    public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID) {
1688        enforceModifyPermissionOrCarrierPrivilege();
1689
1690        if (DBG) log("iccOpenLogicalChannel: " + AID);
1691        IccOpenLogicalChannelResponse response = (IccOpenLogicalChannelResponse)sendRequest(
1692            CMD_OPEN_CHANNEL, AID);
1693        if (DBG) log("iccOpenLogicalChannel: " + response);
1694        return response;
1695    }
1696
1697    @Override
1698    public boolean iccCloseLogicalChannel(int channel) {
1699        enforceModifyPermissionOrCarrierPrivilege();
1700
1701        if (DBG) log("iccCloseLogicalChannel: " + channel);
1702        if (channel < 0) {
1703          return false;
1704        }
1705        Boolean success = (Boolean)sendRequest(CMD_CLOSE_CHANNEL, channel);
1706        if (DBG) log("iccCloseLogicalChannel: " + success);
1707        return success;
1708    }
1709
1710    @Override
1711    public String iccTransmitApduLogicalChannel(int channel, int cla,
1712            int command, int p1, int p2, int p3, String data) {
1713        enforceModifyPermissionOrCarrierPrivilege();
1714
1715        if (DBG) {
1716            log("iccTransmitApduLogicalChannel: chnl=" + channel + " cla=" + cla +
1717                    " cmd=" + command + " p1=" + p1 + " p2=" + p2 + " p3=" + p3 +
1718                    " data=" + data);
1719        }
1720
1721        if (channel < 0) {
1722            return "";
1723        }
1724
1725        IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_LOGICAL_CHANNEL,
1726                new IccAPDUArgument(channel, cla, command, p1, p2, p3, data));
1727        if (DBG) log("iccTransmitApduLogicalChannel: " + response);
1728
1729        // Append the returned status code to the end of the response payload.
1730        String s = Integer.toHexString(
1731                (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1732        if (response.payload != null) {
1733            s = IccUtils.bytesToHexString(response.payload) + s;
1734        }
1735        return s;
1736    }
1737
1738    @Override
1739    public String iccTransmitApduBasicChannel(int cla, int command, int p1, int p2,
1740                int p3, String data) {
1741        enforceModifyPermissionOrCarrierPrivilege();
1742
1743        if (DBG) {
1744            log("iccTransmitApduBasicChannel: cla=" + cla + " cmd=" + command + " p1="
1745                    + p1 + " p2=" + p2 + " p3=" + p3 + " data=" + data);
1746        }
1747
1748        IccIoResult response = (IccIoResult)sendRequest(CMD_TRANSMIT_APDU_BASIC_CHANNEL,
1749                new IccAPDUArgument(0, cla, command, p1, p2, p3, data));
1750        if (DBG) log("iccTransmitApduBasicChannel: " + response);
1751
1752        // Append the returned status code to the end of the response payload.
1753        String s = Integer.toHexString(
1754                (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1755        if (response.payload != null) {
1756            s = IccUtils.bytesToHexString(response.payload) + s;
1757        }
1758        return s;
1759    }
1760
1761    @Override
1762    public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
1763            String filePath) {
1764        enforceModifyPermissionOrCarrierPrivilege();
1765
1766        if (DBG) {
1767            log("Exchange SIM_IO " + fileID + ":" + command + " " +
1768                p1 + " " + p2 + " " + p3 + ":" + filePath);
1769        }
1770
1771        IccIoResult response =
1772            (IccIoResult)sendRequest(CMD_EXCHANGE_SIM_IO,
1773                    new IccAPDUArgument(-1, fileID, command, p1, p2, p3, filePath));
1774
1775        if (DBG) {
1776          log("Exchange SIM_IO [R]" + response);
1777        }
1778
1779        byte[] result = null;
1780        int length = 2;
1781        if (response.payload != null) {
1782            length = 2 + response.payload.length;
1783            result = new byte[length];
1784            System.arraycopy(response.payload, 0, result, 0, response.payload.length);
1785        } else {
1786            result = new byte[length];
1787        }
1788
1789        result[length - 1] = (byte) response.sw2;
1790        result[length - 2] = (byte) response.sw1;
1791        return result;
1792    }
1793
1794    @Override
1795    public String sendEnvelopeWithStatus(String content) {
1796        enforceModifyPermissionOrCarrierPrivilege();
1797
1798        IccIoResult response = (IccIoResult)sendRequest(CMD_SEND_ENVELOPE, content);
1799        if (response.payload == null) {
1800          return "";
1801        }
1802
1803        // Append the returned status code to the end of the response payload.
1804        String s = Integer.toHexString(
1805                (response.sw1 << 8) + response.sw2 + 0x10000).substring(1);
1806        s = IccUtils.bytesToHexString(response.payload) + s;
1807        return s;
1808    }
1809
1810    /**
1811     * Read one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1812     * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1813     *
1814     * @param itemID the ID of the item to read
1815     * @return the NV item as a String, or null on error.
1816     */
1817    @Override
1818    public String nvReadItem(int itemID) {
1819        enforceModifyPermissionOrCarrierPrivilege();
1820        if (DBG) log("nvReadItem: item " + itemID);
1821        String value = (String) sendRequest(CMD_NV_READ_ITEM, itemID);
1822        if (DBG) log("nvReadItem: item " + itemID + " is \"" + value + '"');
1823        return value;
1824    }
1825
1826    /**
1827     * Write one of the NV items defined in {@link com.android.internal.telephony.RadioNVItems}
1828     * and {@code ril_nv_items.h}. Used for device configuration by some CDMA operators.
1829     *
1830     * @param itemID the ID of the item to read
1831     * @param itemValue the value to write, as a String
1832     * @return true on success; false on any failure
1833     */
1834    @Override
1835    public boolean nvWriteItem(int itemID, String itemValue) {
1836        enforceModifyPermissionOrCarrierPrivilege();
1837        if (DBG) log("nvWriteItem: item " + itemID + " value \"" + itemValue + '"');
1838        Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_ITEM,
1839                new Pair<Integer, String>(itemID, itemValue));
1840        if (DBG) log("nvWriteItem: item " + itemID + ' ' + (success ? "ok" : "fail"));
1841        return success;
1842    }
1843
1844    /**
1845     * Update the CDMA Preferred Roaming List (PRL) in the radio NV storage.
1846     * Used for device configuration by some CDMA operators.
1847     *
1848     * @param preferredRoamingList byte array containing the new PRL
1849     * @return true on success; false on any failure
1850     */
1851    @Override
1852    public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) {
1853        enforceModifyPermissionOrCarrierPrivilege();
1854        if (DBG) log("nvWriteCdmaPrl: value: " + HexDump.toHexString(preferredRoamingList));
1855        Boolean success = (Boolean) sendRequest(CMD_NV_WRITE_CDMA_PRL, preferredRoamingList);
1856        if (DBG) log("nvWriteCdmaPrl: " + (success ? "ok" : "fail"));
1857        return success;
1858    }
1859
1860    /**
1861     * Perform the specified type of NV config reset.
1862     * Used for device configuration by some CDMA operators.
1863     *
1864     * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset)
1865     * @return true on success; false on any failure
1866     */
1867    @Override
1868    public boolean nvResetConfig(int resetType) {
1869        enforceModifyPermissionOrCarrierPrivilege();
1870        if (DBG) log("nvResetConfig: type " + resetType);
1871        Boolean success = (Boolean) sendRequest(CMD_NV_RESET_CONFIG, resetType);
1872        if (DBG) log("nvResetConfig: type " + resetType + ' ' + (success ? "ok" : "fail"));
1873        return success;
1874    }
1875
1876    /**
1877     * {@hide}
1878     * Returns Default sim, 0 in the case of single standby.
1879     */
1880    public int getDefaultSim() {
1881        //TODO Need to get it from Telephony Devcontroller
1882        return 0;
1883    }
1884
1885    public String[] getPcscfAddress(String apnType, String callingPackage) {
1886        if (!canReadPhoneState(callingPackage, "getPcscfAddress")) {
1887            return new String[0];
1888        }
1889
1890
1891        return mPhone.getPcscfAddress(apnType);
1892    }
1893
1894    public void setImsRegistrationState(boolean registered) {
1895        enforceModifyPermission();
1896        mPhone.setImsRegistrationState(registered);
1897    }
1898
1899    /**
1900     * Set the network selection mode to automatic.
1901     *
1902     */
1903    @Override
1904    public void setNetworkSelectionModeAutomatic(int subId) {
1905        enforceModifyPermissionOrCarrierPrivilege();
1906        if (DBG) log("setNetworkSelectionModeAutomatic: subId " + subId);
1907        sendRequest(CMD_SET_NETWORK_SELECTION_MODE_AUTOMATIC, null, subId);
1908    }
1909
1910    /**
1911     * Get the calculated preferred network type.
1912     * Used for debugging incorrect network type.
1913     *
1914     * @return the preferred network type, defined in RILConstants.java.
1915     */
1916    @Override
1917    public int getCalculatedPreferredNetworkType(String callingPackage) {
1918        if (!canReadPhoneState(callingPackage, "getCalculatedPreferredNetworkType")) {
1919            return RILConstants.PREFERRED_NETWORK_MODE;
1920        }
1921
1922        return PhoneFactory.calculatePreferredNetworkType(mPhone.getContext(), 0); // wink FIXME: need to get SubId from somewhere.
1923    }
1924
1925    /**
1926     * Get the preferred network type.
1927     * Used for device configuration by some CDMA operators.
1928     *
1929     * @return the preferred network type, defined in RILConstants.java.
1930     */
1931    @Override
1932    public int getPreferredNetworkType(int subId) {
1933        enforceModifyPermissionOrCarrierPrivilege();
1934        if (DBG) log("getPreferredNetworkType");
1935        int[] result = (int[]) sendRequest(CMD_GET_PREFERRED_NETWORK_TYPE, null, subId);
1936        int networkType = (result != null ? result[0] : -1);
1937        if (DBG) log("getPreferredNetworkType: " + networkType);
1938        return networkType;
1939    }
1940
1941    /**
1942     * Set the preferred network type.
1943     * Used for device configuration by some CDMA operators.
1944     *
1945     * @param networkType the preferred network type, defined in RILConstants.java.
1946     * @return true on success; false on any failure.
1947     */
1948    @Override
1949    public boolean setPreferredNetworkType(int subId, int networkType) {
1950        enforceModifyPermissionOrCarrierPrivilege();
1951        if (DBG) log("setPreferredNetworkType: subId " + subId + " type " + networkType);
1952        Boolean success = (Boolean) sendRequest(CMD_SET_PREFERRED_NETWORK_TYPE, networkType, subId);
1953        if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
1954        if (success) {
1955            Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1956                    Settings.Global.PREFERRED_NETWORK_MODE + subId, networkType);
1957        }
1958        return success;
1959    }
1960
1961    /**
1962     * Check TETHER_DUN_REQUIRED and TETHER_DUN_APN settings, net.tethering.noprovisioning
1963     * SystemProperty, and config_tether_apndata to decide whether DUN APN is required for
1964     * tethering.
1965     *
1966     * @return 0: Not required. 1: required. 2: Not set.
1967     * @hide
1968     */
1969    @Override
1970    public int getTetherApnRequired() {
1971        enforceModifyPermissionOrCarrierPrivilege();
1972        int dunRequired = Settings.Global.getInt(mPhone.getContext().getContentResolver(),
1973                Settings.Global.TETHER_DUN_REQUIRED, 2);
1974        // If not set, check net.tethering.noprovisioning, TETHER_DUN_APN setting and
1975        // config_tether_apndata.
1976        if (dunRequired == 2 && mPhone.hasMatchedTetherApnSetting()) {
1977            dunRequired = 1;
1978        }
1979        return dunRequired;
1980    }
1981
1982    /**
1983     * Set mobile data enabled
1984     * Used by the user through settings etc to turn on/off mobile data
1985     *
1986     * @param enable {@code true} turn turn data on, else {@code false}
1987     */
1988    @Override
1989    public void setDataEnabled(int subId, boolean enable) {
1990        enforceModifyPermission();
1991        int phoneId = mSubscriptionController.getPhoneId(subId);
1992        log("getDataEnabled: subId=" + subId + " phoneId=" + phoneId);
1993        Phone phone = PhoneFactory.getPhone(phoneId);
1994        if (phone != null) {
1995            log("setDataEnabled: subId=" + subId + " enable=" + enable);
1996            phone.setDataEnabled(enable);
1997        } else {
1998            loge("setDataEnabled: no phone for subId=" + subId);
1999        }
2000    }
2001
2002    /**
2003     * Get whether mobile data is enabled.
2004     *
2005     * Note that this used to be available from ConnectivityService, gated by
2006     * ACCESS_NETWORK_STATE permission, so this will accept either that or
2007     * our MODIFY_PHONE_STATE.
2008     *
2009     * @return {@code true} if data is enabled else {@code false}
2010     */
2011    @Override
2012    public boolean getDataEnabled(int subId) {
2013        try {
2014            mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
2015                    null);
2016        } catch (Exception e) {
2017            mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
2018                    null);
2019        }
2020        int phoneId = mSubscriptionController.getPhoneId(subId);
2021        log("getDataEnabled: subId=" + subId + " phoneId=" + phoneId);
2022        Phone phone = PhoneFactory.getPhone(phoneId);
2023        if (phone != null) {
2024            boolean retVal = phone.getDataEnabled();
2025            log("getDataEnabled: subId=" + subId + " retVal=" + retVal);
2026            return retVal;
2027        } else {
2028            loge("getDataEnabled: no phone subId=" + subId + " retVal=false");
2029            return false;
2030        }
2031    }
2032
2033    @Override
2034    public int getCarrierPrivilegeStatus() {
2035        UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
2036        if (card == null) {
2037            loge("getCarrierPrivilegeStatus: No UICC");
2038            return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
2039        }
2040        return card.getCarrierPrivilegeStatusForCurrentTransaction(
2041                mPhone.getContext().getPackageManager());
2042    }
2043
2044    @Override
2045    public int checkCarrierPrivilegesForPackage(String pkgName) {
2046        UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
2047        if (card == null) {
2048            loge("checkCarrierPrivilegesForPackage: No UICC");
2049            return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
2050        }
2051        return card.getCarrierPrivilegeStatus(mPhone.getContext().getPackageManager(), pkgName);
2052    }
2053
2054    @Override
2055    public int checkCarrierPrivilegesForPackageAnyPhone(String pkgName) {
2056        int result = TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
2057        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
2058            UiccCard card = UiccController.getInstance().getUiccCard(i);
2059            if (card == null) {
2060              loge("checkCarrierPrivilegesForPackageAnyPhones: No UICC");
2061              continue;
2062            }
2063
2064            result = card.getCarrierPrivilegeStatus(
2065                mPhone.getContext().getPackageManager(), pkgName);
2066            if (result == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
2067                break;
2068            }
2069        }
2070
2071        return result;
2072    }
2073
2074    @Override
2075    public List<String> getCarrierPackageNamesForIntentAndPhone(Intent intent, int phoneId) {
2076        if (!SubscriptionManager.isValidPhoneId(phoneId)) {
2077            loge("phoneId " + phoneId + " is not valid.");
2078            return null;
2079        }
2080        UiccCard card = UiccController.getInstance().getUiccCard(phoneId);
2081        if (card == null) {
2082            loge("getCarrierPackageNamesForIntent: No UICC");
2083            return null ;
2084        }
2085        return card.getCarrierPackageNamesForIntent(
2086                mPhone.getContext().getPackageManager(), intent);
2087    }
2088
2089    private String getIccId(int subId) {
2090        UiccCard card = getPhone(subId).getUiccCard();
2091        if (card == null) {
2092            loge("getIccId: No UICC");
2093            return null;
2094        }
2095        String iccId = card.getIccId();
2096        if (TextUtils.isEmpty(iccId)) {
2097            loge("getIccId: ICC ID is null or empty.");
2098            return null;
2099        }
2100        return iccId;
2101    }
2102
2103    @Override
2104    public boolean setLine1NumberForDisplayForSubscriber(int subId, String alphaTag,
2105            String number) {
2106        enforceCarrierPrivilege();
2107
2108        final String iccId = getIccId(subId);
2109        final String subscriberId = getPhone(subId).getSubscriberId();
2110
2111        if (DBG_MERGE) {
2112            Slog.d(LOG_TAG, "Setting line number for ICC=" + iccId + ", subscriberId="
2113                    + subscriberId + " to " + number);
2114        }
2115
2116        if (TextUtils.isEmpty(iccId)) {
2117            return false;
2118        }
2119
2120        final SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
2121
2122        final String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
2123        if (alphaTag == null) {
2124            editor.remove(alphaTagPrefKey);
2125        } else {
2126            editor.putString(alphaTagPrefKey, alphaTag);
2127        }
2128
2129        // Record both the line number and IMSI for this ICCID, since we need to
2130        // track all merged IMSIs based on line number
2131        final String numberPrefKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
2132        final String subscriberPrefKey = PREF_CARRIERS_SUBSCRIBER_PREFIX + iccId;
2133        if (number == null) {
2134            editor.remove(numberPrefKey);
2135            editor.remove(subscriberPrefKey);
2136        } else {
2137            editor.putString(numberPrefKey, number);
2138            editor.putString(subscriberPrefKey, subscriberId);
2139        }
2140
2141        editor.commit();
2142        return true;
2143    }
2144
2145    @Override
2146    public String getLine1NumberForDisplay(int subId, String callingPackage) {
2147        if (!canReadPhoneState(callingPackage, "getLine1NumberForDisplay")) {
2148            return null;
2149        }
2150
2151        String iccId = getIccId(subId);
2152        if (iccId != null) {
2153            String numberPrefKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
2154            return mTelephonySharedPreferences.getString(numberPrefKey, null);
2155        }
2156        return null;
2157    }
2158
2159    @Override
2160    public String getLine1AlphaTagForDisplay(int subId, String callingPackage) {
2161        if (!canReadPhoneState(callingPackage, "getLine1AlphaTagForDisplay")) {
2162            return null;
2163        }
2164
2165        String iccId = getIccId(subId);
2166        if (iccId != null) {
2167            String alphaTagPrefKey = PREF_CARRIERS_ALPHATAG_PREFIX + iccId;
2168            return mTelephonySharedPreferences.getString(alphaTagPrefKey, null);
2169        }
2170        return null;
2171    }
2172
2173    @Override
2174    public String[] getMergedSubscriberIds() {
2175        final Context context = mPhone.getContext();
2176        final TelephonyManager tele = TelephonyManager.from(context);
2177        final SubscriptionManager sub = SubscriptionManager.from(context);
2178
2179        // Figure out what subscribers are currently active
2180        final ArraySet<String> activeSubscriberIds = new ArraySet<>();
2181        final int[] subIds = sub.getActiveSubscriptionIdList();
2182        for (int subId : subIds) {
2183            activeSubscriberIds.add(tele.getSubscriberId(subId));
2184        }
2185
2186        // First pass, find a number override for an active subscriber
2187        String mergeNumber = null;
2188        final Map<String, ?> prefs = mTelephonySharedPreferences.getAll();
2189        for (String key : prefs.keySet()) {
2190            if (key.startsWith(PREF_CARRIERS_SUBSCRIBER_PREFIX)) {
2191                final String subscriberId = (String) prefs.get(key);
2192                if (activeSubscriberIds.contains(subscriberId)) {
2193                    final String iccId = key.substring(PREF_CARRIERS_SUBSCRIBER_PREFIX.length());
2194                    final String numberKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
2195                    mergeNumber = (String) prefs.get(numberKey);
2196                    if (DBG_MERGE) {
2197                        Slog.d(LOG_TAG, "Found line number " + mergeNumber
2198                                + " for active subscriber " + subscriberId);
2199                    }
2200                    if (!TextUtils.isEmpty(mergeNumber)) {
2201                        break;
2202                    }
2203                }
2204            }
2205        }
2206
2207        // Shortcut when no active merged subscribers
2208        if (TextUtils.isEmpty(mergeNumber)) {
2209            return null;
2210        }
2211
2212        // Second pass, find all subscribers under that line override
2213        final ArraySet<String> result = new ArraySet<>();
2214        for (String key : prefs.keySet()) {
2215            if (key.startsWith(PREF_CARRIERS_NUMBER_PREFIX)) {
2216                final String number = (String) prefs.get(key);
2217                if (mergeNumber.equals(number)) {
2218                    final String iccId = key.substring(PREF_CARRIERS_NUMBER_PREFIX.length());
2219                    final String subscriberKey = PREF_CARRIERS_SUBSCRIBER_PREFIX + iccId;
2220                    final String subscriberId = (String) prefs.get(subscriberKey);
2221                    if (!TextUtils.isEmpty(subscriberId)) {
2222                        result.add(subscriberId);
2223                    }
2224                }
2225            }
2226        }
2227
2228        final String[] resultArray = result.toArray(new String[result.size()]);
2229        Arrays.sort(resultArray);
2230        if (DBG_MERGE) {
2231            Slog.d(LOG_TAG, "Found subscribers " + Arrays.toString(resultArray) + " after merge");
2232        }
2233        return resultArray;
2234    }
2235
2236    @Override
2237    public boolean setOperatorBrandOverride(String brand) {
2238        enforceCarrierPrivilege();
2239        return mPhone.setOperatorBrandOverride(brand);
2240    }
2241
2242    @Override
2243    public boolean setRoamingOverride(List<String> gsmRoamingList,
2244            List<String> gsmNonRoamingList, List<String> cdmaRoamingList,
2245            List<String> cdmaNonRoamingList) {
2246        enforceCarrierPrivilege();
2247        return mPhone.setRoamingOverride(gsmRoamingList, gsmNonRoamingList, cdmaRoamingList,
2248                cdmaNonRoamingList);
2249    }
2250
2251    @Override
2252    public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
2253        enforceModifyPermission();
2254
2255        int returnValue = 0;
2256        try {
2257            AsyncResult result = (AsyncResult)sendRequest(CMD_INVOKE_OEM_RIL_REQUEST_RAW, oemReq);
2258            if(result.exception == null) {
2259                if (result.result != null) {
2260                    byte[] responseData = (byte[])(result.result);
2261                    if(responseData.length > oemResp.length) {
2262                        Log.w(LOG_TAG, "Buffer to copy response too small: Response length is " +
2263                                responseData.length +  "bytes. Buffer Size is " +
2264                                oemResp.length + "bytes.");
2265                    }
2266                    System.arraycopy(responseData, 0, oemResp, 0, responseData.length);
2267                    returnValue = responseData.length;
2268                }
2269            } else {
2270                CommandException ex = (CommandException) result.exception;
2271                returnValue = ex.getCommandError().ordinal();
2272                if(returnValue > 0) returnValue *= -1;
2273            }
2274        } catch (RuntimeException e) {
2275            Log.w(LOG_TAG, "sendOemRilRequestRaw: Runtime Exception");
2276            returnValue = (CommandException.Error.GENERIC_FAILURE.ordinal());
2277            if(returnValue > 0) returnValue *= -1;
2278        }
2279
2280        return returnValue;
2281    }
2282
2283    @Override
2284    public void setRadioCapability(RadioAccessFamily[] rafs) {
2285        try {
2286            ProxyController.getInstance().setRadioCapability(rafs);
2287        } catch (RuntimeException e) {
2288            Log.w(LOG_TAG, "setRadioCapability: Runtime Exception");
2289        }
2290    }
2291
2292    @Override
2293    public int getRadioAccessFamily(int phoneId) {
2294        return ProxyController.getInstance().getRadioAccessFamily(phoneId);
2295    }
2296
2297    @Override
2298    public void enableVideoCalling(boolean enable) {
2299        enforceModifyPermission();
2300        SharedPreferences.Editor editor = mTelephonySharedPreferences.edit();
2301        editor.putBoolean(PREF_ENABLE_VIDEO_CALLING, enable);
2302        editor.commit();
2303    }
2304
2305    @Override
2306    public boolean isVideoCallingEnabled(String callingPackage) {
2307        if (!canReadPhoneState(callingPackage, "isVideoCallingEnabled")) {
2308            return false;
2309        }
2310
2311        // Check the user preference and the  system-level IMS setting. Even if the user has
2312        // enabled video calling, if IMS is disabled we aren't able to support video calling.
2313        // In the long run, we may instead need to check if there exists a connection service
2314        // which can support video calling.
2315        return ImsManager.isVtEnabledByPlatform(mPhone.getContext())
2316                && ImsManager.isEnhanced4gLteModeSettingEnabledByUser(mPhone.getContext())
2317                && mTelephonySharedPreferences.getBoolean(PREF_ENABLE_VIDEO_CALLING, true);
2318    }
2319
2320    @Override
2321    public boolean canChangeDtmfToneLength() {
2322        return mApp.getCarrierConfig().getBoolean(CarrierConfigManager.KEY_DTMF_TYPE_ENABLED_BOOL);
2323    }
2324
2325    @Override
2326    public boolean isWorldPhone() {
2327        return mApp.getCarrierConfig().getBoolean(CarrierConfigManager.KEY_WORLD_PHONE_BOOL);
2328    }
2329
2330    @Override
2331    public boolean isTtyModeSupported() {
2332        TelecomManager telecomManager = TelecomManager.from(mPhone.getContext());
2333        TelephonyManager telephonyManager =
2334                (TelephonyManager) mPhone.getContext().getSystemService(Context.TELEPHONY_SERVICE);
2335        return !telephonyManager.isMultiSimEnabled() && telecomManager.isTtySupported();
2336    }
2337
2338    @Override
2339    public boolean isHearingAidCompatibilitySupported() {
2340        return mPhone.getContext().getResources().getBoolean(R.bool.hac_enabled);
2341    }
2342
2343    /**
2344     * Returns the unique device ID of phone, for example, the IMEI for
2345     * GSM and the MEID for CDMA phones. Return null if device ID is not available.
2346     *
2347     * <p>Requires Permission:
2348     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
2349     */
2350    @Override
2351    public String getDeviceId(String callingPackage) {
2352        if (!canReadPhoneState(callingPackage, "getDeviceId")) {
2353            return null;
2354        }
2355
2356        final Phone phone = PhoneFactory.getPhone(0);
2357        if (phone != null) {
2358            return phone.getDeviceId();
2359        } else {
2360            return null;
2361        }
2362    }
2363
2364    /*
2365     * {@hide}
2366     * Returns the IMS Registration Status
2367     */
2368    @Override
2369    public boolean isImsRegistered() {
2370        return mPhone.isImsRegistered();
2371    }
2372
2373    @Override
2374    public int getSubIdForPhoneAccount(PhoneAccount phoneAccount) {
2375        return PhoneUtils.getSubIdForPhoneAccount(phoneAccount);
2376    }
2377
2378    /*
2379     * {@hide}
2380     * Returns the IMS Registration Status
2381     */
2382    public boolean isWifiCallingEnabled() {
2383        return mPhone.isWifiCallingEnabled();
2384    }
2385
2386    /*
2387     * {@hide}
2388     * Returns the IMS Registration Status
2389     */
2390    public boolean isVolteEnabled() {
2391        return mPhone.isVolteEnabled();
2392    }
2393
2394    private boolean canReadPhoneState(String callingPackage, String message) {
2395        mApp.enforceCallingOrSelfPermission(
2396                android.Manifest.permission.READ_PHONE_STATE, message);
2397
2398        if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
2399                callingPackage) != AppOpsManager.MODE_ALLOWED) {
2400            return false;
2401        }
2402
2403        return true;
2404    }
2405
2406    @Override
2407    public void factoryReset(int subId) {
2408        enforceConnectivityInternalPermission();
2409        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
2410            return;
2411        }
2412
2413        final long identity = Binder.clearCallingIdentity();
2414        try {
2415            if (SubscriptionManager.isUsableSubIdValue(subId) && !mUserManager.hasUserRestriction(
2416                    UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
2417                // Enable data
2418                setDataEnabled(subId, true);
2419                // Set network selection mode to automatic
2420                setNetworkSelectionModeAutomatic(subId);
2421                // Set preferred mobile network type to the best available
2422                setPreferredNetworkType(subId, Phone.PREFERRED_NT_MODE);
2423                // Turn off roaming
2424                SubscriptionManager.from(mApp).setDataRoaming(0, subId);
2425            }
2426        } finally {
2427            Binder.restoreCallingIdentity(identity);
2428        }
2429    }
2430
2431    @Override
2432    public String getLocaleFromDefaultSim() {
2433        // We query all subscriptions instead of just the active ones, because
2434        // this might be called early on in the provisioning flow when the
2435        // subscriptions potentially aren't active yet.
2436        final List<SubscriptionInfo> slist = getAllSubscriptionInfoList();
2437        if (slist == null || slist.isEmpty()) {
2438            return null;
2439        }
2440
2441        // This function may be called very early, say, from the setup wizard, at
2442        // which point we won't have a default subscription set. If that's the case
2443        // we just choose the first, which will be valid in "most cases".
2444        final int defaultSubId = getDefaultSubscription();
2445        SubscriptionInfo info = null;
2446        if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
2447            info = slist.get(0);
2448        } else {
2449            for (SubscriptionInfo item : slist) {
2450                if (item.getSubscriptionId() == defaultSubId) {
2451                    info = item;
2452                    break;
2453                }
2454            }
2455
2456            if (info == null) {
2457                return null;
2458            }
2459        }
2460
2461        // Try and fetch the locale from the carrier properties or from the SIM language
2462        // preferences (EF-PL and EF-LI)...
2463        final Phone defaultPhone = getPhone(info.getSubscriptionId());
2464        if (defaultPhone != null) {
2465            final Locale localeFromDefaultSim = defaultPhone.getLocaleFromSimAndCarrierPrefs();
2466            if (localeFromDefaultSim != null) {
2467                return localeFromDefaultSim.toLanguageTag();
2468            }
2469        }
2470
2471        // .. if that doesn't work, try and guess the language from the sim MCC.
2472        final int mcc = info.getMcc();
2473        final Locale locale = MccTable.getLocaleFromMcc(mPhone.getContext(), mcc);
2474        if (locale != null) {
2475            return locale.toLanguageTag();
2476        }
2477
2478        return null;
2479    }
2480
2481    private List<SubscriptionInfo> getAllSubscriptionInfoList() {
2482        final long identity = Binder.clearCallingIdentity();
2483        try {
2484            return mSubscriptionController.getAllSubInfoList(
2485                    mPhone.getContext().getOpPackageName());
2486        } finally {
2487            Binder.restoreCallingIdentity(identity);
2488        }
2489    }
2490
2491    private List<SubscriptionInfo> getActiveSubscriptionInfoList() {
2492        final long identity = Binder.clearCallingIdentity();
2493        try {
2494            return mSubscriptionController.getActiveSubscriptionInfoList(
2495                    mPhone.getContext().getOpPackageName());
2496        } finally {
2497            Binder.restoreCallingIdentity(identity);
2498        }
2499    }
2500}
2501