17d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon/*
27d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * Copyright (C) 2006 The Android Open Source Project
37d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *
47d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * Licensed under the Apache License, Version 2.0 (the "License");
57d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * you may not use this file except in compliance with the License.
67d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * You may obtain a copy of the License at
77d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *
87d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *      http://www.apache.org/licenses/LICENSE-2.0
97d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *
107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * Unless required by applicable law or agreed to in writing, software
117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * distributed under the License is distributed on an "AS IS" BASIS,
127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * See the License for the specific language governing permissions and
147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * limitations under the License.
157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon */
167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonpackage com.android.phone;
187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.app.ActivityManager;
207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.app.AppOpsManager;
217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.ActivityNotFoundException;
227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.Context;
237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.Intent;
247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.net.ConnectivityManager;
257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.net.Uri;
267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.AsyncResult;
277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Binder;
287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Bundle;
297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Handler;
307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Looper;
317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Message;
327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Process;
337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.ServiceManager;
347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.UserHandle;
357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.telephony.NeighboringCellInfo;
367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.telephony.CellInfo;
377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.telephony.ServiceState;
387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.text.TextUtils;
397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.util.Log;
407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.DefaultPhoneNotifier;
427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.IccCard;
437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.ITelephony;
447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.Phone;
457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.CallManager;
469de0f754068c82ed1d1019afb414bc1fcd9298cfWink Savilleimport com.android.internal.telephony.CommandException;
477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.PhoneConstants;
487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport java.util.List;
507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport java.util.ArrayList;
517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon/**
537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * Implementation of the ITelephony interface.
547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon */
557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonpublic class PhoneInterfaceManager extends ITelephony.Stub {
567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final String LOG_TAG = "PhoneInterfaceManager";
577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final boolean DBG_LOC = false;
597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Message codes used with mMainThreadHandler
617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int CMD_HANDLE_PIN_MMI = 1;
627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int CMD_HANDLE_NEIGHBORING_CELL = 2;
637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int EVENT_NEIGHBORING_CELL_DONE = 3;
647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int CMD_ANSWER_RINGING_CALL = 4;
657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int CMD_END_CALL = 5;  // not used yet
667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int CMD_SILENCE_RINGER = 6;
677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** The singleton instance. */
697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static PhoneInterfaceManager sInstance;
707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    PhoneGlobals mApp;
727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    Phone mPhone;
737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    CallManager mCM;
747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    AppOpsManager mAppOps;
757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    MainThreadHandler mMainThreadHandler;
76406c0341600bd414fe7561b4edd8cdf7ed11f315Santos Cordon    CallHandlerServiceProxy mCallHandlerService;
777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * A request object for use with {@link MainThreadHandler}. Requesters should wait() on the
807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * request after sending. The main thread will notify the request when it is complete.
817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final class MainThreadRequest {
837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        /** The argument to use for the request */
847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public Object argument;
857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        /** The result of the request that is run on the main thread */
867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public Object result;
877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public MainThreadRequest(Object argument) {
897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            this.argument = argument;
907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * A handler that processes messages on the main thread in the phone process. Since many
957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * of the Phone calls are not thread safe this is needed to shuttle the requests from the
967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * inbound binder threads to the main thread in the phone process.  The Binder thread
977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * may provide a {@link MainThreadRequest} object in the msg.obj field that they are waiting
987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * on, which will be notified when the operation completes and will contain the result of the
997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * request.
1007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
1017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <p>If a MainThreadRequest object is provided in the msg.obj field,
1027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * note that request.result must be set to something non-null for the calling thread to
1037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * unblock.
1047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
1057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private final class MainThreadHandler extends Handler {
1067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        @Override
1077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public void handleMessage(Message msg) {
1087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            MainThreadRequest request;
1097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Message onCompleted;
1107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            AsyncResult ar;
1117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            switch (msg.what) {
1137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                case CMD_HANDLE_PIN_MMI:
1147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    request = (MainThreadRequest) msg.obj;
1157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    request.result = Boolean.valueOf(
1167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            mPhone.handlePinMmi((String) request.argument));
1177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Wake up the requesting thread
1187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    synchronized (request) {
1197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        request.notifyAll();
1207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
1217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    break;
1227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                case CMD_HANDLE_NEIGHBORING_CELL:
1247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    request = (MainThreadRequest) msg.obj;
1257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    onCompleted = obtainMessage(EVENT_NEIGHBORING_CELL_DONE,
1267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            request);
1277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    mPhone.getNeighboringCids(onCompleted);
1287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    break;
1297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                case EVENT_NEIGHBORING_CELL_DONE:
1317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    ar = (AsyncResult) msg.obj;
1327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    request = (MainThreadRequest) ar.userObj;
1337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (ar.exception == null && ar.result != null) {
1347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        request.result = ar.result;
1357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else {
1367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // create an empty list to notify the waiting thread
1377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        request.result = new ArrayList<NeighboringCellInfo>();
1387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
1397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Wake up the requesting thread
1407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    synchronized (request) {
1417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        request.notifyAll();
1427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
1437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    break;
1447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                case CMD_ANSWER_RINGING_CALL:
1467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    answerRingingCallInternal();
1477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    break;
1487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                case CMD_SILENCE_RINGER:
1507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    silenceRingerInternal();
1517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    break;
1527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                case CMD_END_CALL:
1547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    request = (MainThreadRequest) msg.obj;
1557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    boolean hungUp = false;
1567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    int phoneType = mPhone.getPhoneType();
1577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
1587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // CDMA: If the user presses the Power button we treat it as
1597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // ending the complete call session
1607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        hungUp = PhoneUtils.hangupRingingAndActive(mPhone);
1617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
1627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // GSM: End the call as per the Phone state
1637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        hungUp = PhoneUtils.hangup(mCM);
1647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else {
1657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        throw new IllegalStateException("Unexpected phone type: " + phoneType);
1667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
1677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("CMD_END_CALL: " + (hungUp ? "hung up!" : "no call to hang up"));
1687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    request.result = hungUp;
1697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Wake up the requesting thread
1707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    synchronized (request) {
1717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        request.notifyAll();
1727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
1737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    break;
1747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                default:
1767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
1777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    break;
1787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
1797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
1807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
1817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
1837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Posts the specified command to be executed on the main thread,
1847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * waits for the request to complete, and returns the result.
1857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see #sendRequestAsync
1867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
1877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private Object sendRequest(int command, Object argument) {
1887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
1897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new RuntimeException("This method will deadlock if called from the main thread.");
1907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
1917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        MainThreadRequest request = new MainThreadRequest(argument);
1937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Message msg = mMainThreadHandler.obtainMessage(command, request);
1947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        msg.sendToTarget();
1957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Wait for the request to complete
1977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        synchronized (request) {
1987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            while (request.result == null) {
1997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                try {
2007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    request.wait();
2017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } catch (InterruptedException e) {
2027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Do nothing, go back and wait until the request is complete
2037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
2047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
2057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return request.result;
2077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
2107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Asynchronous ("fire and forget") version of sendRequest():
2117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Posts the specified command to be executed on the main thread, and
2127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * returns immediately.
2137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see #sendRequest
2147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
2157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private void sendRequestAsync(int command) {
2167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mMainThreadHandler.sendEmptyMessage(command);
2177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
2207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Initialize the singleton PhoneInterfaceManager instance.
2217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This is only done once, at startup, from PhoneApp.onCreate().
2227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
223406c0341600bd414fe7561b4edd8cdf7ed11f315Santos Cordon    /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone,
224406c0341600bd414fe7561b4edd8cdf7ed11f315Santos Cordon            CallHandlerServiceProxy callHandlerService) {
2257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        synchronized (PhoneInterfaceManager.class) {
2267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (sInstance == null) {
227406c0341600bd414fe7561b4edd8cdf7ed11f315Santos Cordon                sInstance = new PhoneInterfaceManager(app, phone, callHandlerService);
2287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
2297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
2307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
2317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return sInstance;
2327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Private constructor; @see init() */
236406c0341600bd414fe7561b4edd8cdf7ed11f315Santos Cordon    private PhoneInterfaceManager(PhoneGlobals app, Phone phone,
237406c0341600bd414fe7561b4edd8cdf7ed11f315Santos Cordon            CallHandlerServiceProxy callHandlerService) {
2387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mApp = app;
2397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mPhone = phone;
2407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mCM = PhoneGlobals.getInstance().mCM;
2417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
2427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mMainThreadHandler = new MainThreadHandler();
243406c0341600bd414fe7561b4edd8cdf7ed11f315Santos Cordon        mCallHandlerService = callHandlerService;
2447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        publish();
2457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private void publish() {
2487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("publish: " + this);
2497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        ServiceManager.addService("phone", this);
2517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
2547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Implementation of the ITelephony interface.
2557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
2567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public void dial(String number) {
2587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("dial: " + number);
2597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // No permission check needed here: This is just a wrapper around the
2607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // ACTION_DIAL intent, which is available to any app since it puts up
2617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the UI before it does anything.
2627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String url = createTelUrl(number);
2647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (url == null) {
2657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return;
2667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // PENDING: should we just silently fail if phone is offhook or ringing?
2697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        PhoneConstants.State state = mCM.getState();
2707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (state != PhoneConstants.State.OFFHOOK && state != PhoneConstants.State.RINGING) {
2717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Intent  intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
2727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            mApp.startActivity(intent);
2747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public void call(String callingPackage, String number) {
2787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("call: " + number);
2797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // This is just a wrapper around the ACTION_CALL intent, but we still
2817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // need to do a permission check since we're calling startActivity()
2827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // from the context of the phone app.
2837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceCallPermission();
2847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (mAppOps.noteOp(AppOpsManager.OP_CALL_PHONE, Binder.getCallingUid(), callingPackage)
2867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                != AppOpsManager.MODE_ALLOWED) {
2877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return;
2887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String url = createTelUrl(number);
2917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (url == null) {
2927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return;
2937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
2967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mApp.startActivity(intent);
2987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private boolean showCallScreenInternal(boolean specifyInitialDialpadState,
301bcf2099b92870b863f53e79288d4c8e73a4dc42dMakoto Onuki                                           boolean showDialpad) {
3027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!PhoneGlobals.sVoiceCapable) {
3037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Never allow the InCallScreen to appear on data-only devices.
3047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
3057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (isIdle()) {
3077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
3087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // If the phone isn't idle then go to the in-call screen
3107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        long callingId = Binder.clearCallingIdentity();
311406c0341600bd414fe7561b4edd8cdf7ed11f315Santos Cordon
312bcf2099b92870b863f53e79288d4c8e73a4dc42dMakoto Onuki        mCallHandlerService.bringToForeground(showDialpad);
313406c0341600bd414fe7561b4edd8cdf7ed11f315Santos Cordon
314406c0341600bd414fe7561b4edd8cdf7ed11f315Santos Cordon        Binder.restoreCallingIdentity(callingId);
3157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return true;
3167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Show the in-call screen without specifying the initial dialpad state.
3197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean showCallScreen() {
3207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return showCallScreenInternal(false, false);
3217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // The variation of showCallScreen() that specifies the initial dialpad state.
3247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // (Ideally this would be called showCallScreen() too, just with a different
3257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // signature, but AIDL doesn't allow that.)
3267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean showCallScreenWithDialpad(boolean showDialpad) {
3277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return showCallScreenInternal(true, showDialpad);
3287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
3317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * End a call based on call state
3327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true is a call was ended
3337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
3347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean endCall() {
3357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceCallPermission();
3367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return (Boolean) sendRequest(CMD_END_CALL, null);
3377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public void answerRingingCall() {
3407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("answerRingingCall...");
3417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: there should eventually be a separate "ANSWER_PHONE" permission,
3427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // but that can probably wait till the big TelephonyManager API overhaul.
3437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // For now, protect this call with the MODIFY_PHONE_STATE permission.
3447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceModifyPermission();
3457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        sendRequestAsync(CMD_ANSWER_RINGING_CALL);
3467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
3497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Make the actual telephony calls to implement answerRingingCall().
3507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This should only be called from the main thread of the Phone app.
3517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see #answerRingingCall
3527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
3537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * TODO: it would be nice to return true if we answered the call, or
3547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * false if there wasn't actually a ringing incoming call, or some
3557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * other error occurred.  (In other words, pass back the return value
3567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * from PhoneUtils.answerCall() or PhoneUtils.answerAndEndActive().)
3577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * But that would require calling this method via sendRequest() rather
3587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * than sendRequestAsync(), and right now we don't actually *need* that
3597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * return value, so let's just return void for now.
3607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
3617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private void answerRingingCallInternal() {
3627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean hasRingingCall = !mPhone.getRingingCall().isIdle();
3637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (hasRingingCall) {
3647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean hasActiveCall = !mPhone.getForegroundCall().isIdle();
3657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean hasHoldingCall = !mPhone.getBackgroundCall().isIdle();
3667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (hasActiveCall && hasHoldingCall) {
3677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Both lines are in use!
3687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // TODO: provide a flag to let the caller specify what
3697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // policy to use if both lines are in use.  (The current
3707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // behavior is hardwired to "answer incoming, end ongoing",
3717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // which is how the CALL button is specced to behave.)
3727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                PhoneUtils.answerAndEndActive(mCM, mCM.getFirstActiveRingingCall());
3737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return;
3747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
3757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // answerCall() will automatically hold the current active
3767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // call, if there is one.
3777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
3787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return;
3797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
3807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
3817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // No call was ringing.
3827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return;
3837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public void silenceRinger() {
3877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("silenceRinger...");
3887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: find a more appropriate permission to check here.
3897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // (That can probably wait till the big TelephonyManager API overhaul.
3907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // For now, protect this call with the MODIFY_PHONE_STATE permission.)
3917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceModifyPermission();
3927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        sendRequestAsync(CMD_SILENCE_RINGER);
3937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
3967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Internal implemenation of silenceRinger().
3977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This should only be called from the main thread of the Phone app.
3987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see #silenceRinger
3997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
4007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private void silenceRingerInternal() {
4017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if ((mCM.getState() == PhoneConstants.State.RINGING)
4027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            && mApp.notifier.isRinging()) {
4037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Ringer is actually playing, so silence it.
4047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("silenceRingerInternal: silencing...");
4057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            mApp.notifier.silenceRinger();
4067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean isOffhook() {
4107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return (mCM.getState() == PhoneConstants.State.OFFHOOK);
4117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean isRinging() {
4147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return (mCM.getState() == PhoneConstants.State.RINGING);
4157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean isIdle() {
4187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return (mCM.getState() == PhoneConstants.State.IDLE);
4197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean isSimPinEnabled() {
4227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceReadPermission();
4237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return (PhoneGlobals.getInstance().isSimPinEnabled());
4247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean supplyPin(String pin) {
4279de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville        int [] resultArray = supplyPinReportResult(pin);
4289de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville        return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
4299de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville    }
4309de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville
4319de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville    public boolean supplyPuk(String puk, String pin) {
4329de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville        int [] resultArray = supplyPukReportResult(puk, pin);
4339de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville        return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
4349de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville    }
4359de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville
4369de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville    /** {@hide} */
4379de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville    public int[] supplyPinReportResult(String pin) {
4387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceModifyPermission();
4397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final UnlockSim checkSimPin = new UnlockSim(mPhone.getIccCard());
4407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        checkSimPin.start();
4417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return checkSimPin.unlockSim(null, pin);
4427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4449de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville    /** {@hide} */
4459de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville    public int[] supplyPukReportResult(String puk, String pin) {
4467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceModifyPermission();
4477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final UnlockSim checkSimPuk = new UnlockSim(mPhone.getIccCard());
4487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        checkSimPuk.start();
4497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return checkSimPuk.unlockSim(puk, pin);
4507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
4539de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville     * Helper thread to turn async call to SimCard#supplyPin into
4547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * a synchronous one.
4557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
4567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static class UnlockSim extends Thread {
4577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        private final IccCard mSimCard;
4597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        private boolean mDone = false;
4619de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville        private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
4629de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville        private int mRetryCount = -1;
4637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // For replies from SimCard interface
4657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        private Handler mHandler;
4667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // For async handler to identify request type
4687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        private static final int SUPPLY_PIN_COMPLETE = 100;
4697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public UnlockSim(IccCard simCard) {
4717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            mSimCard = simCard;
4727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        @Override
4757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public void run() {
4767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Looper.prepare();
4777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            synchronized (UnlockSim.this) {
4787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                mHandler = new Handler() {
4797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    @Override
4807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    public void handleMessage(Message msg) {
4817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        AsyncResult ar = (AsyncResult) msg.obj;
4827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        switch (msg.what) {
4837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            case SUPPLY_PIN_COMPLETE:
4847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
4857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                synchronized (UnlockSim.this) {
4869de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville                                    mRetryCount = msg.arg1;
4879de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville                                    if (ar.exception != null) {
4889de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville                                        if (ar.exception instanceof CommandException &&
4899de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville                                                ((CommandException)(ar.exception)).getCommandError()
4909de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville                                                == CommandException.Error.PASSWORD_INCORRECT) {
4919de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville                                            mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
4929de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville                                        } else {
4939de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville                                            mResult = PhoneConstants.PIN_GENERAL_FAILURE;
4949de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville                                        }
4959de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville                                    } else {
4969de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville                                        mResult = PhoneConstants.PIN_RESULT_SUCCESS;
4979de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville                                    }
4987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    mDone = true;
4997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    UnlockSim.this.notifyAll();
5007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                }
5017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                break;
5027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
5037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
5047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                };
5057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                UnlockSim.this.notifyAll();
5067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
5077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Looper.loop();
5087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        /*
5117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon         * Use PIN or PUK to unlock SIM card
5127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon         *
5137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon         * If PUK is null, unlock SIM card with PIN
5147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon         *
5157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon         * If PUK is not null, unlock SIM card with PUK and set PIN code
5167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon         */
5179de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville        synchronized int[] unlockSim(String puk, String pin) {
5187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            while (mHandler == null) {
5207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                try {
5217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    wait();
5227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } catch (InterruptedException e) {
5237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    Thread.currentThread().interrupt();
5247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
5257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
5267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Message callback = Message.obtain(mHandler, SUPPLY_PIN_COMPLETE);
5277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (puk == null) {
5297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                mSimCard.supplyPin(pin, callback);
5307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
5317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                mSimCard.supplyPuk(puk, pin, callback);
5327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
5337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            while (!mDone) {
5357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                try {
5367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    Log.d(LOG_TAG, "wait for done");
5377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    wait();
5387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } catch (InterruptedException e) {
5397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Restore the interrupted status
5407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    Thread.currentThread().interrupt();
5417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
5427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
5437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.d(LOG_TAG, "done");
5449de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville            int[] resultArray = new int[2];
5459de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville            resultArray[0] = mResult;
5469de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville            resultArray[1] = mRetryCount;
5479de0f754068c82ed1d1019afb414bc1fcd9298cfWink Saville            return resultArray;
5487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public void updateServiceLocation() {
5527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // No permission check needed here: this call is harmless, and it's
5537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // needed for the ServiceState.requestStateUpdate() call (which is
5547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // already intentionally exposed to 3rd parties.)
5557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mPhone.updateServiceLocation();
5567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean isRadioOn() {
5597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return mPhone.getServiceState().getVoiceRegState() != ServiceState.STATE_POWER_OFF;
5607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public void toggleRadioOnOff() {
5637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceModifyPermission();
5647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mPhone.setRadioPower(!isRadioOn());
5657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean setRadio(boolean turnOn) {
5677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceModifyPermission();
5687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if ((mPhone.getServiceState().getVoiceRegState() != ServiceState.STATE_POWER_OFF) != turnOn) {
5697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            toggleRadioOnOff();
5707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return true;
5727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean setRadioPower(boolean turnOn) {
5747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceModifyPermission();
5757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mPhone.setRadioPower(turnOn);
5767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return true;
5777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean enableDataConnectivity() {
5807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceModifyPermission();
5817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        ConnectivityManager cm =
5827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                (ConnectivityManager)mApp.getSystemService(Context.CONNECTIVITY_SERVICE);
5837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        cm.setMobileDataEnabled(true);
5847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return true;
5857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public int enableApnType(String type) {
5887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceModifyPermission();
5897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return mPhone.enableApnType(type);
5907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public int disableApnType(String type) {
5937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceModifyPermission();
5947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return mPhone.disableApnType(type);
5957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean disableDataConnectivity() {
5987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceModifyPermission();
5997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        ConnectivityManager cm =
6007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                (ConnectivityManager)mApp.getSystemService(Context.CONNECTIVITY_SERVICE);
6017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        cm.setMobileDataEnabled(false);
6027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return true;
6037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean isDataConnectivityPossible() {
6067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return mPhone.isDataConnectivityPossible();
6077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean handlePinMmi(String dialString) {
6107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceModifyPermission();
6117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return (Boolean) sendRequest(CMD_HANDLE_PIN_MMI, dialString);
6127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public void cancelMissedCallsNotification() {
6157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        enforceModifyPermission();
6167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mApp.notificationMgr.cancelMissedCallNotification();
6177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public int getCallState() {
6207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return DefaultPhoneNotifier.convertCallState(mCM.getState());
6217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public int getDataState() {
6247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return DefaultPhoneNotifier.convertDataState(mPhone.getDataConnectionState());
6257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public int getDataActivity() {
6287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return DefaultPhoneNotifier.convertDataActivityState(mPhone.getDataActivityState());
6297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @Override
6327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public Bundle getCellLocation() {
6337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
6347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            mApp.enforceCallingOrSelfPermission(
6357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                android.Manifest.permission.ACCESS_FINE_LOCATION, null);
6367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (SecurityException e) {
6377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
6387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
6397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // is the weaker precondition
6407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            mApp.enforceCallingOrSelfPermission(
6417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
6427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (checkIfCallerIsSelfOrForegoundUser()) {
6457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG_LOC) log("getCellLocation: is active user");
6467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Bundle data = new Bundle();
6477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            mPhone.getCellLocation().fillInNotifierBundle(data);
6487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return data;
6497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
6507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG_LOC) log("getCellLocation: suppress non-active user");
6517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return null;
6527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @Override
6567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public void enableLocationUpdates() {
6577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mApp.enforceCallingOrSelfPermission(
6587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
6597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mPhone.enableLocationUpdates();
6607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @Override
6637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public void disableLocationUpdates() {
6647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mApp.enforceCallingOrSelfPermission(
6657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                android.Manifest.permission.CONTROL_LOCATION_UPDATES, null);
6667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mPhone.disableLocationUpdates();
6677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @Override
6707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @SuppressWarnings("unchecked")
6717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
6727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
6737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            mApp.enforceCallingOrSelfPermission(
6747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    android.Manifest.permission.ACCESS_FINE_LOCATION, null);
6757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (SecurityException e) {
6767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // If we have ACCESS_FINE_LOCATION permission, skip the check
6777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // for ACCESS_COARSE_LOCATION
6787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // A failure should throw the SecurityException from
6797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // ACCESS_COARSE_LOCATION since this is the weaker precondition
6807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            mApp.enforceCallingOrSelfPermission(
6817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
6827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (mAppOps.noteOp(AppOpsManager.OP_NEIGHBORING_CELLS, Binder.getCallingUid(),
6857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                callingPackage) != AppOpsManager.MODE_ALLOWED) {
6867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return null;
6877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (checkIfCallerIsSelfOrForegoundUser()) {
6897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG_LOC) log("getNeighboringCellInfo: is active user");
6907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            ArrayList<NeighboringCellInfo> cells = null;
6927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            try {
6947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cells = (ArrayList<NeighboringCellInfo>) sendRequest(
6957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        CMD_HANDLE_NEIGHBORING_CELL, null);
6967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } catch (RuntimeException e) {
6977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.e(LOG_TAG, "getNeighboringCellInfo " + e);
6987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
6997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return cells;
7007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
7017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG_LOC) log("getNeighboringCellInfo: suppress non-active user");
7027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return null;
7037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @Override
7087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public List<CellInfo> getAllCellInfo() {
7097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
7107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            mApp.enforceCallingOrSelfPermission(
7117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                android.Manifest.permission.ACCESS_FINE_LOCATION, null);
7127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (SecurityException e) {
7137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // If we have ACCESS_FINE_LOCATION permission, skip the check for ACCESS_COARSE_LOCATION
7147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // A failure should throw the SecurityException from ACCESS_COARSE_LOCATION since this
7157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // is the weaker precondition
7167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            mApp.enforceCallingOrSelfPermission(
7177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
7187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (checkIfCallerIsSelfOrForegoundUser()) {
7217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG_LOC) log("getAllCellInfo: is active user");
7227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return mPhone.getAllCellInfo();
7237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
7247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG_LOC) log("getAllCellInfo: suppress non-active user");
7257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return null;
7267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public void setCellInfoListRate(int rateInMillis) {
7307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mPhone.setCellInfoListRate(rateInMillis);
7317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
7347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Internal helper methods.
7357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
7367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private boolean checkIfCallerIsSelfOrForegoundUser() {
7387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean ok;
7397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean self = Binder.getCallingUid() == Process.myUid();
7417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!self) {
7427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Get the caller's user id then clear the calling identity
7437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // which will be restored in the finally clause.
7447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            int callingUser = UserHandle.getCallingUserId();
7457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            long ident = Binder.clearCallingIdentity();
7467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            try {
7487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // With calling identity cleared the current user is the foreground user.
7497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                int foregroundUser = ActivityManager.getCurrentUser();
7507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                ok = (foregroundUser == callingUser);
7517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG_LOC) {
7527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    log("checkIfCallerIsSelfOrForegoundUser: foregroundUser=" + foregroundUser
7537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            + " callingUser=" + callingUser + " ok=" + ok);
7547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
7557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } catch (Exception ex) {
7567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG_LOC) loge("checkIfCallerIsSelfOrForegoundUser: Exception ex=" + ex);
7577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                ok = false;
7587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } finally {
7597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Binder.restoreCallingIdentity(ident);
7607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
7617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
7627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: is self");
7637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            ok = true;
7647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG_LOC) log("checkIfCallerIsSelfOrForegoundUser: ret=" + ok);
7667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return ok;
7677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
7707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Make sure the caller has the READ_PHONE_STATE permission.
7717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
7727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @throws SecurityException if the caller does not have the required permission
7737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
7747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private void enforceReadPermission() {
7757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, null);
7767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
7797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Make sure the caller has the MODIFY_PHONE_STATE permission.
7807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
7817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @throws SecurityException if the caller does not have the required permission
7827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
7837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private void enforceModifyPermission() {
7847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
7857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
7887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Make sure the caller has the CALL_PHONE permission.
7897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
7907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @throws SecurityException if the caller does not have the required permission
7917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
7927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private void enforceCallPermission() {
7937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mApp.enforceCallingOrSelfPermission(android.Manifest.permission.CALL_PHONE, null);
7947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private String createTelUrl(String number) {
7987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (TextUtils.isEmpty(number)) {
7997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return null;
8007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
8017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        StringBuilder buf = new StringBuilder("tel:");
8037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        buf.append(number);
8047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return buf.toString();
8057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private void log(String msg) {
8087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "[PhoneIntfMgr] " + msg);
8097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private void loge(String msg) {
8127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.e(LOG_TAG, "[PhoneIntfMgr] " + msg);
8137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public int getActivePhoneType() {
8167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return mPhone.getPhoneType();
8177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns the CDMA ERI icon index to display
8217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public int getCdmaEriIconIndex() {
8237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return mPhone.getCdmaEriIconIndex();
8247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns the CDMA ERI icon mode,
8287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * 0 - ON
8297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * 1 - FLASHING
8307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public int getCdmaEriIconMode() {
8327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return mPhone.getCdmaEriIconMode();
8337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns the CDMA ERI text,
8377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public String getCdmaEriText() {
8397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return mPhone.getCdmaEriText();
8407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns true if CDMA provisioning needs to run.
8447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean needsOtaServiceProvisioning() {
8467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return mPhone.needsOtaServiceProvisioning();
8477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns the unread count of voicemails
8517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public int getVoiceMessageCount() {
8537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return mPhone.getVoiceMessageCount();
8547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns the data network type
8587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
8597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @Deprecated to be removed Q3 2013 use {@link #getDataNetworkType}.
8607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @Override
8627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public int getNetworkType() {
8637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return mPhone.getServiceState().getDataNetworkType();
8647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns the data network type
8687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @Override
8707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public int getDataNetworkType() {
8717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return mPhone.getServiceState().getDataNetworkType();
8727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns the data network type
8767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @Override
8787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public int getVoiceNetworkType() {
8797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return mPhone.getServiceState().getVoiceNetworkType();
8807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if a ICC card is present
8847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public boolean hasIccCard() {
8867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return mPhone.getIccCard().hasIccCard();
8877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Return if the current radio is LTE on CDMA. This
8917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * is a tri-state return value as for a period of time
8927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * the mode may be unknown.
8937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
8947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
8957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * or {@link PHone#LTE_ON_CDMA_TRUE}
8967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public int getLteOnCdmaMode() {
8987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return mPhone.getLteOnCdmaMode();
8997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
9007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon}
901