OutgoingCallBroadcaster.java revision da120f4e3d32ca97c5b4c21d6c505d834a29ab8d
17d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon/*
27d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * Copyright (C) 2008 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.Activity;
207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.app.ActivityManagerNative;
217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.app.AlertDialog;
227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.app.AppOpsManager;
237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.app.Dialog;
247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.BroadcastReceiver;
257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.Context;
267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.DialogInterface;
277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.Intent;
287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.res.Configuration;
29d3105fe2f9f544fccd2cddbb1ab977dfe157b56eYorke Leeimport android.content.res.Resources;
307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.net.Uri;
317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Binder;
327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Bundle;
337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Handler;
347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Message;
357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.RemoteException;
367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.SystemProperties;
377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.UserHandle;
387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.telephony.PhoneNumberUtils;
397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.text.TextUtils;
407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.util.Log;
417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.view.View;
427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.widget.ProgressBar;
437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.Phone;
457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.PhoneConstants;
467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.TelephonyCapabilities;
477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon/**
49c65769e202f771137686574bb097ee3f7aaccdfaSantos Cordon * OutgoingCallBroadcaster receives CALL and CALL_PRIVILEGED Intents, and broadcasts the
50c65769e202f771137686574bb097ee3f7aaccdfaSantos Cordon * ACTION_NEW_OUTGOING_CALL intent. ACTION_NEW_OUTGOING_CALL is an ordered broadcast intent which
51c65769e202f771137686574bb097ee3f7aaccdfaSantos Cordon * contains the phone number being dialed. Applications can use this intent to (1) see which numbers
52c65769e202f771137686574bb097ee3f7aaccdfaSantos Cordon * are being dialed, (2) redirect a call (change the number being dialed), or (3) prevent a call
53c65769e202f771137686574bb097ee3f7aaccdfaSantos Cordon * from being placed.
54c65769e202f771137686574bb097ee3f7aaccdfaSantos Cordon *
557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * After the other applications have had a chance to see the
567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * ACTION_NEW_OUTGOING_CALL intent, it finally reaches the
577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * {@link OutgoingCallReceiver}, which passes the (possibly modified)
587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * intent on to the {@link SipCallOptionHandler}, which will
597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * ultimately start the call using the CallController.placeCall() API.
607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *
61c65769e202f771137686574bb097ee3f7aaccdfaSantos Cordon * Calls where no number is present (like for a CDMA "empty flash" or a nonexistent voicemail
62c65769e202f771137686574bb097ee3f7aaccdfaSantos Cordon * number) are exempt from being broadcast.
63c65769e202f771137686574bb097ee3f7aaccdfaSantos Cordon * Calls to emergency numbers are still broadcast for informative purposes. The call is placed
64c65769e202f771137686574bb097ee3f7aaccdfaSantos Cordon * prior to sending ACTION_NEW_OUTGOING_CALL and cannot be redirected nor prevented.
657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon */
667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonpublic class OutgoingCallBroadcaster extends Activity
677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final String TAG = "OutgoingCallBroadcaster";
707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final boolean DBG =
717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Do not check in with VDBG = true, since that may write PII to the system log.
737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final boolean VDBG = false;
747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
75c65769e202f771137686574bb097ee3f7aaccdfaSantos Cordon    /** Required permission for any app that wants to consume ACTION_NEW_OUTGOING_CALL. */
76c65769e202f771137686574bb097ee3f7aaccdfaSantos Cordon    private static final String PERMISSION = android.Manifest.permission.PROCESS_OUTGOING_CALLS;
77c65769e202f771137686574bb097ee3f7aaccdfaSantos Cordon
787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static final String ACTION_SIP_SELECT_PHONE = "com.android.phone.SIP_SELECT_PHONE";
797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static final String EXTRA_ALREADY_CALLED = "android.phone.extra.ALREADY_CALLED";
807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static final String EXTRA_ORIGINAL_URI = "android.phone.extra.ORIGINAL_URI";
817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static final String EXTRA_NEW_CALL_INTENT = "android.phone.extra.NEW_CALL_INTENT";
827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static final String EXTRA_SIP_PHONE_URI = "android.phone.extra.SIP_PHONE_URI";
837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static final String EXTRA_ACTUAL_NUMBER_TO_DIAL =
847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            "android.phone.extra.ACTUAL_NUMBER_TO_DIAL";
85bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal    public static final String EXTRA_THIRD_PARTY_CALL_COMPONENT =
86bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal            "android.phone.extra.THIRD_PARTY_CALL_COMPONENT";
877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Identifier for intent extra for sending an empty Flash message for
907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * CDMA networks. This message is used by the network to simulate a
917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * press/depress of the "hookswitch" of a landline phone. Aka "empty flash".
927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * TODO: Receiving an intent extra to tell the phone to send this flash is a
947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * temporary measure. To be replaced with an external ITelephony call in the future.
957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * TODO: Keep in sync with the string defined in TwelveKeyDialer.java in Contacts app
967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * until this is replaced with the ITelephony API.
977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static final String EXTRA_SEND_EMPTY_FLASH =
997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            "com.android.phone.extra.SEND_EMPTY_FLASH";
1007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Dialog IDs
1027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int DIALOG_NOT_VOICE_CAPABLE = 1;
1037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Note message codes < 100 are reserved for the PhoneApp. */
1057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int EVENT_OUTGOING_CALL_TIMEOUT = 101;
1067d86bec92eaa062ae56ddb906199839da7805022Santos Cordon    private static final int EVENT_DELAYED_FINISH = 102;
1077d86bec92eaa062ae56ddb906199839da7805022Santos Cordon
1087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int OUTGOING_CALL_TIMEOUT_THRESHOLD = 2000; // msec
1097d86bec92eaa062ae56ddb906199839da7805022Santos Cordon    private static final int DELAYED_FINISH_TIME = 2000; // msec
1107d86bec92eaa062ae56ddb906199839da7805022Santos Cordon
1117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
1127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * ProgressBar object with "spinner" style, which will be shown if we take more than
1137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * {@link #EVENT_OUTGOING_CALL_TIMEOUT} msec to handle the incoming Intent.
1147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
1157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private ProgressBar mWaitingSpinner;
1167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private final Handler mHandler = new Handler() {
1177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        @Override
1187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public void handleMessage(Message msg) {
1197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (msg.what == EVENT_OUTGOING_CALL_TIMEOUT) {
1207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.i(TAG, "Outgoing call takes too long. Showing the spinner.");
1217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                mWaitingSpinner.setVisibility(View.VISIBLE);
1227d86bec92eaa062ae56ddb906199839da7805022Santos Cordon            } else if (msg.what == EVENT_DELAYED_FINISH) {
1237d86bec92eaa062ae56ddb906199839da7805022Santos Cordon                finish();
1247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
1257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.wtf(TAG, "Unknown message id: " + msg.what);
1267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
1277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
1287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    };
1297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
1317d86bec92eaa062ae56ddb906199839da7805022Santos Cordon     * Starts the delayed finish() of OutgoingCallBroadcaster in order to give the UI
1327d86bec92eaa062ae56ddb906199839da7805022Santos Cordon     * some time to start up.
1337d86bec92eaa062ae56ddb906199839da7805022Santos Cordon     */
1347d86bec92eaa062ae56ddb906199839da7805022Santos Cordon    private void startDelayedFinish() {
1357d86bec92eaa062ae56ddb906199839da7805022Santos Cordon        mHandler.sendEmptyMessageDelayed(EVENT_DELAYED_FINISH, DELAYED_FINISH_TIME);
1367d86bec92eaa062ae56ddb906199839da7805022Santos Cordon    }
1377d86bec92eaa062ae56ddb906199839da7805022Santos Cordon
1387d86bec92eaa062ae56ddb906199839da7805022Santos Cordon    /**
1397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * OutgoingCallReceiver finishes NEW_OUTGOING_CALL broadcasts, starting
1407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * the InCallScreen if the broadcast has not been canceled, possibly with
1417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * a modified phone number and optional provider info (uri + package name + remote views.)
1427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
1437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public class OutgoingCallReceiver extends BroadcastReceiver {
1447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        private static final String TAG = "OutgoingCallReceiver";
1457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        @Override
1477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public void onReceive(Context context, Intent intent) {
1487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            mHandler.removeMessages(EVENT_OUTGOING_CALL_TIMEOUT);
1494ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon            final boolean isAttemptingCall = doReceive(context, intent);
1507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) Log.v(TAG, "OutgoingCallReceiver is going to finish the Activity itself.");
1517d86bec92eaa062ae56ddb906199839da7805022Santos Cordon
1527d86bec92eaa062ae56ddb906199839da7805022Santos Cordon            // We cannot finish the activity immediately here because it would cause the temporary
1537d86bec92eaa062ae56ddb906199839da7805022Santos Cordon            // black screen of OutgoingBroadcaster to go away and we need it to stay up until the
1547d86bec92eaa062ae56ddb906199839da7805022Santos Cordon            // UI (in a different process) has time to come up.
1554ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon            // However, if we know we are not attemping a call, we need to finish the activity
1564ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon            // immediately so that subsequent CALL intents will retrigger a new
1574ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon            // OutgoingCallReceiver. see b/10857203
1584ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon            if (isAttemptingCall) {
1594ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon                startDelayedFinish();
1604ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon            } else {
1614ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon                finish();
1624ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon            }
1637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
1647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1654ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon
1664ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon        /**
1674ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon         * Handes receipt of ordered new_outgoing_call intent. Verifies that the return from the
1684ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon         * ordered intent is valid.
1694ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon         * @return true if the call is being attempted; false if we are canceling the call.
1704ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon         */
1714ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon        public boolean doReceive(Context context, Intent intent) {
1727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) Log.v(TAG, "doReceive: " + intent);
1737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            boolean alreadyCalled;
1757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            String number;
1767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            String originalUri;
1777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            alreadyCalled = intent.getBooleanExtra(
1797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    OutgoingCallBroadcaster.EXTRA_ALREADY_CALLED, false);
1807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (alreadyCalled) {
1817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) Log.v(TAG, "CALL already placed -- returning.");
1824ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon                return false;
1837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
1847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Once the NEW_OUTGOING_CALL broadcast is finished, the resultData
1867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // is used as the actual number to call. (If null, no call will be
1877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // placed.)
1887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            number = getResultData();
1907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (VDBG) Log.v(TAG, "- got number from resultData: '" + number + "'");
1917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final PhoneGlobals app = PhoneGlobals.getInstance();
1937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // OTASP-specific checks.
1957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // TODO: This should probably all happen in
1967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // OutgoingCallBroadcaster.onCreate(), since there's no reason to
1977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // even bother with the NEW_OUTGOING_CALL broadcast if we're going
1987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // to disallow the outgoing call anyway...
1997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (TelephonyCapabilities.supportsOtasp(app.phone)) {
2007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                boolean activateState = (app.cdmaOtaScreenState.otaScreenState
2017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        == OtaUtils.CdmaOtaScreenState.OtaScreenState.OTA_STATUS_ACTIVATION);
2027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                boolean dialogState = (app.cdmaOtaScreenState.otaScreenState
2037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        == OtaUtils.CdmaOtaScreenState.OtaScreenState
2047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .OTA_STATUS_SUCCESS_FAILURE_DLG);
2057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                boolean isOtaCallActive = false;
2067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // TODO: Need cleaner way to check if OTA is active.
2087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Also, this check seems to be broken in one obscure case: if
2097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // you interrupt an OTASP call by pressing Back then Skip,
2107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // otaScreenState somehow gets left in either PROGRESS or
2117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // LISTENING.
2127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if ((app.cdmaOtaScreenState.otaScreenState
2137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        == OtaUtils.CdmaOtaScreenState.OtaScreenState.OTA_STATUS_PROGRESS)
2147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        || (app.cdmaOtaScreenState.otaScreenState
2157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        == OtaUtils.CdmaOtaScreenState.OtaScreenState.OTA_STATUS_LISTENING)) {
2167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    isOtaCallActive = true;
2177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
2187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (activateState || dialogState) {
2207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // The OTASP sequence is active, but either (1) the call
2217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // hasn't started yet, or (2) the call has ended and we're
2227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // showing the success/failure screen.  In either of these
2237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // cases it's OK to make a new outgoing call, but we need
2247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // to take down any OTASP-related UI first.
2257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (dialogState) app.dismissOtaDialogs();
2267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    app.clearOtaState();
2277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else if (isOtaCallActive) {
2287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // The actual OTASP call is active.  Don't allow new
2297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // outgoing calls at all from this state.
2307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    Log.w(TAG, "OTASP call is active: disallowing a new outgoing call.");
2314ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon                    return false;
2327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
2337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
2347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (number == null) {
2367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) Log.v(TAG, "CALL cancelled (null number), returning...");
2374ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon                return false;
2387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else if (TelephonyCapabilities.supportsOtasp(app.phone)
2397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && (app.phone.getState() != PhoneConstants.State.IDLE)
2407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && (app.phone.isOtaSpNumber(number))) {
2417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) Log.v(TAG, "Call is active, a 2nd OTA call cancelled -- returning.");
2424ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon                return false;
24336bb2546cbc86a4e6d338c3c31bbd02c4602b5e2Yorke Lee            } else if (PhoneNumberUtils.isPotentialLocalEmergencyNumber(context, number)) {
2447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Just like 3rd-party apps aren't allowed to place emergency
2457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // calls via the ACTION_CALL intent, we also don't allow 3rd
2467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // party apps to use the NEW_OUTGOING_CALL broadcast to rewrite
2477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // an outgoing call into an emergency number.
2487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.w(TAG, "Cannot modify outgoing call to emergency number " + number + ".");
2494ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon                return false;
2507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
2517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            originalUri = intent.getStringExtra(
2537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    OutgoingCallBroadcaster.EXTRA_ORIGINAL_URI);
2547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (originalUri == null) {
2557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.e(TAG, "Intent is missing EXTRA_ORIGINAL_URI -- returning.");
2564ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon                return false;
2577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
2587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Uri uri = Uri.parse(originalUri);
2607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // We already called convertKeypadLettersToDigits() and
2627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // stripSeparators() way back in onCreate(), before we sent out the
2637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // NEW_OUTGOING_CALL broadcast.  But we need to do it again here
2647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // too, since the number might have been modified/rewritten during
2657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // the broadcast (and may now contain letters or separators again.)
2667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            number = PhoneNumberUtils.convertKeypadLettersToDigits(number);
2677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            number = PhoneNumberUtils.stripSeparators(number);
2687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) Log.v(TAG, "doReceive: proceeding with call...");
2707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (VDBG) Log.v(TAG, "- uri: " + uri);
2717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (VDBG) Log.v(TAG, "- actual number to dial: '" + number + "'");
2727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            startSipCallOptionHandler(context, intent, uri, number);
2744ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon
2754ebe45dd5aea839774bfb5adefd635356ffe2154Santos Cordon            return true;
2767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
2807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Launch the SipCallOptionHandler, which is the next step(*) in the
2817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * outgoing-call sequence after the outgoing call broadcast is
2827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * complete.
2837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
2847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * (*) We now know exactly what phone number we need to dial, so the next
2857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *     step is for the SipCallOptionHandler to decide which Phone type (SIP
2867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *     or PSTN) should be used.  (Depending on the user's preferences, this
2877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *     decision may also involve popping up a dialog to ask the user to
2887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *     choose what type of call this should be.)
2897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
2907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context used for the startActivity() call
2917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
2927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param intent the intent from the previous step of the outgoing-call
2937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   sequence.  Normally this will be the NEW_OUTGOING_CALL broadcast intent
2947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   that came in to the OutgoingCallReceiver, although it can also be the
2957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   original ACTION_CALL intent that started the whole sequence (in cases
2967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   where we don't do the NEW_OUTGOING_CALL broadcast at all, like for
2977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   emergency numbers or SIP addresses).
2987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
2997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param uri the data URI from the original CALL intent, presumably either
3007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   a tel: or sip: URI.  For tel: URIs, note that the scheme-specific part
3017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   does *not* necessarily have separators and keypad letters stripped (so
3027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   we might see URIs like "tel:(650)%20555-1234" or "tel:1-800-GOOG-411"
3037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   here.)
3047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
3057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param number the actual number (or SIP address) to dial.  This is
3067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   guaranteed to be either a PSTN phone number with separators stripped
3077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   out and keypad letters converted to digits (like "16505551234"), or a
3087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   raw SIP address (like "user@example.com").
3097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
3107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private void startSipCallOptionHandler(Context context, Intent intent,
3117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Uri uri, String number) {
312da120f4e3d32ca97c5b4c21d6c505d834a29ab8dSantos Cordon        // TODO: Remove this code.
3137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
3167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This method is the single point of entry for the CALL intent, which is used (by built-in
3177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * apps like Contacts / Dialer, as well as 3rd-party apps) to initiate an outgoing voice call.
3187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
3197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
3207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
3217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @Override
3227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    protected void onCreate(Bundle icicle) {
3237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        super.onCreate(icicle);
3247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        setContentView(R.layout.outgoing_call_broadcaster);
3257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mWaitingSpinner = (ProgressBar) findViewById(R.id.spinner);
3267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Intent intent = getIntent();
3287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) {
3297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final Configuration configuration = getResources().getConfiguration();
3307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.v(TAG, "onCreate: this = " + this + ", icicle = " + icicle);
3317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.v(TAG, " - getIntent() = " + intent);
3327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.v(TAG, " - configuration = " + configuration);
3337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (icicle != null) {
3367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // A non-null icicle means that this activity is being
3377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // re-initialized after previously being shut down.
3387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //
3397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // In practice this happens very rarely (because the lifetime
3407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // of this activity is so short!), but it *can* happen if the
3417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // framework detects a configuration change at exactly the
3427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // right moment; see bug 2202413.
3437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //
3447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // In this case, do nothing.  Our onCreate() method has already
3457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // run once (with icicle==null the first time), which means
3467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // that the NEW_OUTGOING_CALL broadcast for this new call has
3477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // already been sent.
3487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.i(TAG, "onCreate: non-null icicle!  "
3497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                  + "Bailing out, not sending NEW_OUTGOING_CALL broadcast...");
3507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // No need to finish() here, since the OutgoingCallReceiver from
3527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // our original instance will do that.  (It'll actually call
3537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // finish() on our original instance, which apparently works fine
3547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // even though the ActivityManager has already shut that instance
3557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // down.  And note that if we *do* call finish() here, that just
3567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // results in an "ActivityManager: Duplicate finish request"
3577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // warning when the OutgoingCallReceiver runs.)
3587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return;
3607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        processIntent(intent);
3637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // isFinishing() return false when 1. broadcast is still ongoing, or 2. dialog is being
3657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // shown. Otherwise finish() is called inside processIntent(), is isFinishing() here will
3667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // return true.
3677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) Log.v(TAG, "At the end of onCreate(). isFinishing(): " + isFinishing());
3687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
3717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Interprets a given Intent and starts something relevant to the Intent.
3727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
3737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This method will handle three kinds of actions:
3747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
3757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * - CALL (action for usual outgoing voice calls)
3767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * - CALL_PRIVILEGED (can come from built-in apps like contacts / voice dialer / bluetooth)
3777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * - CALL_EMERGENCY (from the EmergencyDialer that's reachable from the lockscreen.)
3787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
3797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * The exact behavior depends on the intent's data:
3807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
3817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * - The most typical is a tel: URI, which we handle by starting the
3827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   NEW_OUTGOING_CALL broadcast.  That broadcast eventually triggers
3837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   the sequence OutgoingCallReceiver -> SipCallOptionHandler ->
3847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   InCallScreen.
3857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
3867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * - Or, with a sip: URI we skip the NEW_OUTGOING_CALL broadcast and
3877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   go directly to SipCallOptionHandler, which then leads to the
3887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   InCallScreen.
3897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
3907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * - voicemail: URIs take the same path as regular tel: URIs.
3917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
3927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Other special cases:
3937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
3947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * - Outgoing calls are totally disallowed on non-voice-capable
3957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   devices (see handleNonVoiceCapable()).
3967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
3977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * - A CALL intent with the EXTRA_SEND_EMPTY_FLASH extra (and
3987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   presumably no data at all) means "send an empty flash" (which
3997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   is only meaningful on CDMA devices while a call is already
4007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   active.)
4017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
4027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
4037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private void processIntent(Intent intent) {
4047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) {
4057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.v(TAG, "processIntent() = " + intent + ", thread: " + Thread.currentThread());
4067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final Configuration configuration = getResources().getConfiguration();
4087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Outgoing phone calls are only allowed on "voice-capable" devices.
4107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!PhoneGlobals.sVoiceCapable) {
4117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.i(TAG, "This device is detected as non-voice-capable device.");
4127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            handleNonVoiceCapable(intent);
4137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return;
4147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String action = intent.getAction();
4177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String number = PhoneNumberUtils.getNumberFromIntent(intent, this);
4187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Check the number, don't convert for sip uri
4197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO put uriNumber under PhoneNumberUtils
4207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (number != null) {
4217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (!PhoneNumberUtils.isUriNumber(number)) {
4227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                number = PhoneNumberUtils.convertKeypadLettersToDigits(number);
4237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                number = PhoneNumberUtils.stripSeparators(number);
4247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
4257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
4267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(TAG, "The number obtained from Intent is null.");
4277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        AppOpsManager appOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE);
4307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int launchedFromUid;
4317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String launchedFromPackage;
4327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
4337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            launchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
4347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    getActivityToken());
4357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            launchedFromPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
4367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    getActivityToken());
4377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (RemoteException e) {
4387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            launchedFromUid = -1;
4397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            launchedFromPackage = null;
4407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
441829b26ee6d940957aa48f964e94db3ce6d9ccbe7Dianne Hackborn        if (appOps.noteOpNoThrow(AppOpsManager.OP_CALL_PHONE, launchedFromUid, launchedFromPackage)
4427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                != AppOpsManager.MODE_ALLOWED) {
4437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(TAG, "Rejecting call from uid " + launchedFromUid + " package "
4447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + launchedFromPackage);
4457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            finish();
4467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return;
4477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // If true, this flag will indicate that the current call is a special kind
4507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // of call (most likely an emergency number) that 3rd parties aren't allowed
4517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // to intercept or affect in any way.  (In that case, we start the call
4527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // immediately rather than going through the NEW_OUTGOING_CALL sequence.)
4537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean callNow;
4547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (getClass().getName().equals(intent.getComponent().getClassName())) {
4567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // If we were launched directly from the OutgoingCallBroadcaster,
4577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // not one of its more privileged aliases, then make sure that
4587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // only the non-privileged actions are allowed.
4597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (!Intent.ACTION_CALL.equals(intent.getAction())) {
4607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.w(TAG, "Attempt to deliver non-CALL action; forcing to CALL");
4617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                intent.setAction(Intent.ACTION_CALL);
4627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
4637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Check whether or not this is an emergency number, in order to
4667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // enforce the restriction that only the CALL_PRIVILEGED and
4677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // CALL_EMERGENCY intents are allowed to make emergency calls.
4687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
4697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // (Note that the ACTION_CALL check below depends on the result of
4707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // isPotentialLocalEmergencyNumber() rather than just plain
4717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // isLocalEmergencyNumber(), to be 100% certain that we *don't*
4727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // allow 3rd party apps to make emergency calls by passing in an
4737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // "invalid" number like "9111234" that isn't technically an
4747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // emergency number but might still result in an emergency call
4757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // with some networks.)
4767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean isExactEmergencyNumber =
47736bb2546cbc86a4e6d338c3c31bbd02c4602b5e2Yorke Lee                (number != null) && PhoneNumberUtils.isLocalEmergencyNumber(this, number);
4787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean isPotentialEmergencyNumber =
47936bb2546cbc86a4e6d338c3c31bbd02c4602b5e2Yorke Lee                (number != null) && PhoneNumberUtils.isPotentialLocalEmergencyNumber(this, number);
4807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (VDBG) {
4817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.v(TAG, " - Checking restrictions for number '" + number + "':");
4827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.v(TAG, "     isExactEmergencyNumber     = " + isExactEmergencyNumber);
4837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.v(TAG, "     isPotentialEmergencyNumber = " + isPotentialEmergencyNumber);
4847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        /* Change CALL_PRIVILEGED into CALL or CALL_EMERGENCY as needed. */
4877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: This code is redundant with some code in InCallScreen: refactor.
4887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (Intent.ACTION_CALL_PRIVILEGED.equals(action)) {
4897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // We're handling a CALL_PRIVILEGED intent, so we know this request came
4907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // from a trusted source (like the built-in dialer.)  So even a number
4917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // that's *potentially* an emergency number can safely be promoted to
4927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // CALL_EMERGENCY (since we *should* allow you to dial "91112345" from
4937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // the dialer if you really want to.)
4947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (isPotentialEmergencyNumber) {
4957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.i(TAG, "ACTION_CALL_PRIVILEGED is used while the number is a potential"
4967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        + " emergency number. Use ACTION_CALL_EMERGENCY as an action instead.");
4977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                action = Intent.ACTION_CALL_EMERGENCY;
4987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
4997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                action = Intent.ACTION_CALL;
5007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
5017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) Log.v(TAG, " - updating action from CALL_PRIVILEGED to " + action);
5027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            intent.setAction(action);
5037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (Intent.ACTION_CALL.equals(action)) {
5067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (isPotentialEmergencyNumber) {
5077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.w(TAG, "Cannot call potential emergency number '" + number
5087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        + "' with CALL Intent " + intent + ".");
5097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.i(TAG, "Launching default dialer instead...");
5107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Intent invokeFrameworkDialer = new Intent();
5127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // TwelveKeyDialer is in a tab so we really want
5147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // DialtactsActivity.  Build the intent 'manually' to
5157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // use the java resolver to find the dialer class (as
5167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // opposed to a Context which look up known android
5177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // packages only)
518d3105fe2f9f544fccd2cddbb1ab977dfe157b56eYorke Lee                final Resources resources = getResources();
519d3105fe2f9f544fccd2cddbb1ab977dfe157b56eYorke Lee                invokeFrameworkDialer.setClassName(
520d3105fe2f9f544fccd2cddbb1ab977dfe157b56eYorke Lee                        resources.getString(R.string.ui_default_package),
521d3105fe2f9f544fccd2cddbb1ab977dfe157b56eYorke Lee                        resources.getString(R.string.dialer_default_class));
5227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                invokeFrameworkDialer.setAction(Intent.ACTION_DIAL);
5237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                invokeFrameworkDialer.setData(intent.getData());
5247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) Log.v(TAG, "onCreate(): calling startActivity for Dialer: "
5257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                               + invokeFrameworkDialer);
5267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                startActivity(invokeFrameworkDialer);
5277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                finish();
5287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return;
5297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
5307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            callNow = false;
5317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {
5327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // ACTION_CALL_EMERGENCY case: this is either a CALL_PRIVILEGED
5337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // intent that we just turned into a CALL_EMERGENCY intent (see
5347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // above), or else it really is an CALL_EMERGENCY intent that
5357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // came directly from some other app (e.g. the EmergencyDialer
5367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // activity built in to the Phone app.)
5377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Make sure it's at least *possible* that this is really an
5387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // emergency number.
5397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (!isPotentialEmergencyNumber) {
5407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.w(TAG, "Cannot call non-potential-emergency number " + number
5417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        + " with EMERGENCY_CALL Intent " + intent + "."
5427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        + " Finish the Activity immediately.");
5437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                finish();
5447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return;
5457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
5467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            callNow = true;
5477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
5487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.e(TAG, "Unhandled Intent " + intent + ". Finish the Activity immediately.");
5497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            finish();
5507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return;
5517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Make sure the screen is turned on.  This is probably the right
5547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // thing to do, and more importantly it works around an issue in the
5557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // activity manager where we will not launch activities consistently
5567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // when the screen is off (since it is trying to keep them paused
5577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // and has...  issues).
5587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
5597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Also, this ensures the device stays awake while doing the following
5607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // broadcast; technically we should be holding a wake lock here
5617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // as well.
5627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        PhoneGlobals.getInstance().wakeUpScreen();
5637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // If number is null, we're probably trying to call a non-existent voicemail number,
5657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // send an empty flash or something else is fishy.  Whatever the problem, there's no
5667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // number, so there's no point in allowing apps to modify the number.
5677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (TextUtils.isEmpty(number)) {
5687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (intent.getBooleanExtra(EXTRA_SEND_EMPTY_FLASH, false)) {
5697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.i(TAG, "onCreate: SEND_EMPTY_FLASH...");
5707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                PhoneUtils.sendEmptyFlash(PhoneGlobals.getPhone());
5717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                finish();
5727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return;
5737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
5747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.i(TAG, "onCreate: null or empty number, setting callNow=true...");
5757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                callNow = true;
5767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
5777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (callNow) {
5807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // This is a special kind of call (most likely an emergency number)
5817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // that 3rd parties aren't allowed to intercept or affect in any way.
5827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // So initiate the outgoing call immediately.
5837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.i(TAG, "onCreate(): callNow case! Calling placeCall(): " + intent);
5857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Initiate the outgoing call, and simultaneously launch the
5877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // InCallScreen to display the in-call UI:
5887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneGlobals.getInstance().callController.placeCall(intent);
5897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Note we do *not* "return" here, but instead continue and
5917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // send the ACTION_NEW_OUTGOING_CALL broadcast like for any
5927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // other outgoing call.  (But when the broadcast finally
5937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // reaches the OutgoingCallReceiver, we'll know not to
5947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // initiate the call again because of the presence of the
5957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // EXTRA_ALREADY_CALLED extra.)
5967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // For now, SIP calls will be processed directly without a
5997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // NEW_OUTGOING_CALL broadcast.
6007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
6017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: In the future, though, 3rd party apps *should* be allowed to
6027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // intercept outgoing calls to SIP addresses as well.  To do this, we should
6037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // (1) update the NEW_OUTGOING_CALL intent documentation to explain this
6047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // case, and (2) pass the outgoing SIP address by *not* overloading the
6057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // EXTRA_PHONE_NUMBER extra, but instead using a new separate extra to hold
6067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the outgoing SIP address.  (Be sure to document whether it's a URI or just
6077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // a plain address, whether it could be a tel: URI, etc.)
6087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Uri uri = intent.getData();
6097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String scheme = uri.getScheme();
6107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (Constants.SCHEME_SIP.equals(scheme) || PhoneNumberUtils.isUriNumber(number)) {
6117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.i(TAG, "The requested number was detected as SIP call.");
6127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            startSipCallOptionHandler(this, intent, uri, number);
6137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            finish();
6147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return;
6157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // TODO: if there's ever a way for SIP calls to trigger a
6177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // "callNow=true" case (see above), we'll need to handle that
6187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // case here too (most likely by just doing nothing at all.)
6197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
6227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (number != null) {
6237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
6247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
62569a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon        CallGatewayManager.checkAndCopyPhoneProviderExtras(intent, broadcastIntent);
6267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        broadcastIntent.putExtra(EXTRA_ALREADY_CALLED, callNow);
6277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        broadcastIntent.putExtra(EXTRA_ORIGINAL_URI, uri.toString());
6287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Need to raise foreground in-call UI as soon as possible while allowing 3rd party app
6297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // to intercept the outgoing call.
6307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
6317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) Log.v(TAG, " - Broadcasting intent: " + broadcastIntent + ".");
6327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Set a timer so that we can prepare for unexpected delay introduced by the broadcast.
6347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // If it takes too much time, the timer will show "waiting" spinner.
6357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // This message will be removed when OutgoingCallReceiver#onReceive() is called before the
6367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // timeout.
6377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mHandler.sendEmptyMessageDelayed(EVENT_OUTGOING_CALL_TIMEOUT,
6387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                OUTGOING_CALL_TIMEOUT_THRESHOLD);
6397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        sendOrderedBroadcastAsUser(broadcastIntent, UserHandle.OWNER,
6407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                PERMISSION, new OutgoingCallReceiver(),
6417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                null,  // scheduler
6427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Activity.RESULT_OK,  // initialCode
6437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                number,  // initialData: initial value for the result data
6447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                null);  // initialExtras
6457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @Override
6487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    protected void onStop() {
6497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Clean up (and dismiss if necessary) any managed dialogs.
6507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
6517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // We don't do this in onPause() since we can be paused/resumed
6527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // due to orientation changes (in which case we don't want to
6537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // disturb the dialog), but we *do* need it here in onStop() to be
6547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // sure we clean up if the user hits HOME while the dialog is up.
6557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
6567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Note it's safe to call removeDialog() even if there's no dialog
6577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // associated with that ID.
6587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        removeDialog(DIALOG_NOT_VOICE_CAPABLE);
6597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        super.onStop();
6617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
6647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Handle the specified CALL or CALL_* intent on a non-voice-capable
6657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * device.
6667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
6677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This method may launch a different intent (if there's some useful
6687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * alternative action to take), or otherwise display an error dialog,
6697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * and in either case will finish() the current activity when done.
6707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
6717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private void handleNonVoiceCapable(Intent intent) {
6727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) Log.v(TAG, "handleNonVoiceCapable: handling " + intent
6737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                       + " on non-voice-capable device...");
6747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
67588653e75f7dc4494e54728ce13b15f296c3e6f82Chiao Cheng        // Just show a generic "voice calling not supported" dialog.
6767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        showDialog(DIALOG_NOT_VOICE_CAPABLE);
6777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // ...and we'll eventually finish() when the user dismisses
6787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // or cancels the dialog.
6797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @Override
6827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    protected Dialog onCreateDialog(int id) {
6837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Dialog dialog;
6847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        switch(id) {
6857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case DIALOG_NOT_VOICE_CAPABLE:
6867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                dialog = new AlertDialog.Builder(this)
6877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setTitle(R.string.not_voice_capable)
6887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setIconAttribute(android.R.attr.alertDialogIcon)
6897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setPositiveButton(android.R.string.ok, this)
6907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setOnCancelListener(this)
6917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .create();
6927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
6937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            default:
6947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.w(TAG, "onCreateDialog: unexpected ID " + id);
6957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                dialog = null;
6967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
6977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return dialog;
6997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** DialogInterface.OnClickListener implementation */
7027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @Override
7037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public void onClick(DialogInterface dialog, int id) {
7047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // DIALOG_NOT_VOICE_CAPABLE is the only dialog we ever use (so far
7057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // at least), and its only button is "OK".
7067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        finish();
7077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** DialogInterface.OnCancelListener implementation */
7107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @Override
7117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public void onCancel(DialogInterface dialog) {
7127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // DIALOG_NOT_VOICE_CAPABLE is the only dialog we ever use (so far
7137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // at least), and canceling it is just like hitting "OK".
7147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        finish();
7157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
7187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Implement onConfigurationChanged() purely for debugging purposes,
7197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * to make sure that the android:configChanges element in our manifest
7207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * is working properly.
7217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
7227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @Override
7237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public void onConfigurationChanged(Configuration newConfig) {
7247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        super.onConfigurationChanged(newConfig);
7257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) Log.v(TAG, "onConfigurationChanged: newConfig = " + newConfig);
7267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon}
728