1b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/*
2b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *
4b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * you may not use this file except in compliance with the License.
6b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * You may obtain a copy of the License at
7b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *
8b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *
10b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * See the License for the specific language governing permissions and
14b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * limitations under the License.
15b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */
16b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
17b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectpackage com.android.phone;
18b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
19b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.app.Activity;
20f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackbornimport android.app.ActivityManagerNative;
216c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brownimport android.app.AlertDialog;
22f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackbornimport android.app.AppOpsManager;
236c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brownimport android.app.Dialog;
24b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.BroadcastReceiver;
25b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Context;
266c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brownimport android.content.DialogInterface;
27b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Intent;
287291a106eb69b365de60a9452c5fc31828e2db8eDavid Brownimport android.content.res.Configuration;
29b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.net.Uri;
30f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackbornimport android.os.Binder;
31b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Bundle;
32ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawaimport android.os.Handler;
33ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawaimport android.os.Message;
34f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackbornimport android.os.RemoteException;
356b0efb615a5b1a65984192384c88965fa7dd06a0David Brownimport android.os.SystemProperties;
3691177a70c9024522c1d0d3ac570124998f09647aDianne Hackbornimport android.os.UserHandle;
37b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.telephony.PhoneNumberUtils;
38008791ca2a9a1406c2a9f7b39c794104d151b898Paul Bermanimport android.text.TextUtils;
39b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.util.Log;
40ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawaimport android.view.View;
41ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawaimport android.widget.ProgressBar;
42b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
436b0efb615a5b1a65984192384c88965fa7dd06a0David Brownimport com.android.internal.telephony.Phone;
44b0f85b4a78abead921c363f9c8e247d5bdd20c74Wink Savilleimport com.android.internal.telephony.PhoneConstants;
45f8a9fbe31969b4f97ea03d233684efc117888879Daisuke Miyakawaimport com.android.internal.telephony.TelephonyCapabilities;
461ca2b2b333a7c22b728d648d3592ee064762dd00Shaopeng Jia
47b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/**
486b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * OutgoingCallBroadcaster receives CALL and CALL_PRIVILEGED Intents, and
496b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * broadcasts the ACTION_NEW_OUTGOING_CALL intent which allows other
506b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * applications to monitor, redirect, or prevent the outgoing call.
516b0efb615a5b1a65984192384c88965fa7dd06a0David Brown
526b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * After the other applications have had a chance to see the
536b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * ACTION_NEW_OUTGOING_CALL intent, it finally reaches the
546b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * {@link OutgoingCallReceiver}, which passes the (possibly modified)
558ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown * intent on to the {@link SipCallOptionHandler}, which will
568ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown * ultimately start the call using the CallController.placeCall() API.
57b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *
586b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * Emergency calls and calls where no number is present (like for a CDMA
596b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * "empty flash" or a nonexistent voicemail number) are exempt from being
606b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * broadcast.
61b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */
626c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brownpublic class OutgoingCallBroadcaster extends Activity
636c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
64b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
65b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final String PERMISSION = android.Manifest.permission.PROCESS_OUTGOING_CALLS;
66b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final String TAG = "OutgoingCallBroadcaster";
676b0efb615a5b1a65984192384c88965fa7dd06a0David Brown    private static final boolean DBG =
68a1a9601840e50e18ff8ca4be9b888e592287577bDianne Hackborn            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
69a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown    // Do not check in with VDBG = true, since that may write PII to the system log.
70a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown    private static final boolean VDBG = false;
71b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
7275e3711d82d0c98444f6c438437cad41d862fca6David Brown    public static final String ACTION_SIP_SELECT_PHONE = "com.android.phone.SIP_SELECT_PHONE";
73b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static final String EXTRA_ALREADY_CALLED = "android.phone.extra.ALREADY_CALLED";
74b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static final String EXTRA_ORIGINAL_URI = "android.phone.extra.ORIGINAL_URI";
752587d9c6437b680911e252efecc73788e876de76Chung-yih Wang    public static final String EXTRA_NEW_CALL_INTENT = "android.phone.extra.NEW_CALL_INTENT";
762587d9c6437b680911e252efecc73788e876de76Chung-yih Wang    public static final String EXTRA_SIP_PHONE_URI = "android.phone.extra.SIP_PHONE_URI";
778ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown    public static final String EXTRA_ACTUAL_NUMBER_TO_DIAL =
788ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            "android.phone.extra.ACTUAL_NUMBER_TO_DIAL";
79b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
80e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn    /**
81008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * Identifier for intent extra for sending an empty Flash message for
82008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * CDMA networks. This message is used by the network to simulate a
83008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * press/depress of the "hookswitch" of a landline phone. Aka "empty flash".
84008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     *
85008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * TODO: Receiving an intent extra to tell the phone to send this flash is a
86008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * temporary measure. To be replaced with an external ITelephony call in the future.
87008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * TODO: Keep in sync with the string defined in TwelveKeyDialer.java in Contacts app
88008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * until this is replaced with the ITelephony API.
89008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     */
90ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    public static final String EXTRA_SEND_EMPTY_FLASH =
91ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            "com.android.phone.extra.SEND_EMPTY_FLASH";
92008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman
936c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    // Dialog IDs
946c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    private static final int DIALOG_NOT_VOICE_CAPABLE = 1;
956c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
96ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    /** Note message codes < 100 are reserved for the PhoneApp. */
97ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    private static final int EVENT_OUTGOING_CALL_TIMEOUT = 101;
98ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    private static final int OUTGOING_CALL_TIMEOUT_THRESHOLD = 2000; // msec
99ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    /**
100ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * ProgressBar object with "spinner" style, which will be shown if we take more than
101ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * {@link #EVENT_OUTGOING_CALL_TIMEOUT} msec to handle the incoming Intent.
102ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     */
103ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    private ProgressBar mWaitingSpinner;
104ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    private final Handler mHandler = new Handler() {
105ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa        @Override
106ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa        public void handleMessage(Message msg) {
107ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            if (msg.what == EVENT_OUTGOING_CALL_TIMEOUT) {
108ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa                Log.i(TAG, "Outgoing call takes too long. Showing the spinner.");
109ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa                mWaitingSpinner.setVisibility(View.VISIBLE);
110ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            } else {
111ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa                Log.wtf(TAG, "Unknown message id: " + msg.what);
112ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            }
113ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa        }
114ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    };
115ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa
116008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman    /**
117e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn     * OutgoingCallReceiver finishes NEW_OUTGOING_CALL broadcasts, starting
118e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn     * the InCallScreen if the broadcast has not been canceled, possibly with
119e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn     * a modified phone number and optional provider info (uri + package name + remote views.)
120e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn     */
121e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn    public class OutgoingCallReceiver extends BroadcastReceiver {
122e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn        private static final String TAG = "OutgoingCallReceiver";
123e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
124ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa        @Override
125e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn        public void onReceive(Context context, Intent intent) {
12608ad9a53367c93ab76dbc1d2c7a58681a6533cf8Daisuke Miyakawa            mHandler.removeMessages(EVENT_OUTGOING_CALL_TIMEOUT);
127e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            doReceive(context, intent);
128ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            if (DBG) Log.v(TAG, "OutgoingCallReceiver is going to finish the Activity itself.");
129e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            finish();
130e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn        }
131008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman
132e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn        public void doReceive(Context context, Intent intent) {
1336b0efb615a5b1a65984192384c88965fa7dd06a0David Brown            if (DBG) Log.v(TAG, "doReceive: " + intent);
1346b0efb615a5b1a65984192384c88965fa7dd06a0David Brown
135e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            boolean alreadyCalled;
136e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            String number;
137e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            String originalUri;
138e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
139e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            alreadyCalled = intent.getBooleanExtra(
140e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                    OutgoingCallBroadcaster.EXTRA_ALREADY_CALLED, false);
141e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            if (alreadyCalled) {
1426b0efb615a5b1a65984192384c88965fa7dd06a0David Brown                if (DBG) Log.v(TAG, "CALL already placed -- returning.");
143e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                return;
144e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            }
145e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
1468ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // Once the NEW_OUTGOING_CALL broadcast is finished, the resultData
1478ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // is used as the actual number to call. (If null, no call will be
1488ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // placed.)
1498ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown
150e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            number = getResultData();
151a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown            if (VDBG) Log.v(TAG, "- got number from resultData: '" + number + "'");
1528ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown
153a1a9601840e50e18ff8ca4be9b888e592287577bDianne Hackborn            final PhoneGlobals app = PhoneGlobals.getInstance();
1548343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
1557c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown            // OTASP-specific checks.
1567c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown            // TODO: This should probably all happen in
1577c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown            // OutgoingCallBroadcaster.onCreate(), since there's no reason to
1587c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown            // even bother with the NEW_OUTGOING_CALL broadcast if we're going
1597c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown            // to disallow the outgoing call anyway...
1608343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            if (TelephonyCapabilities.supportsOtasp(app.phone)) {
161e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                boolean activateState = (app.cdmaOtaScreenState.otaScreenState
162e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                        == OtaUtils.CdmaOtaScreenState.OtaScreenState.OTA_STATUS_ACTIVATION);
163e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                boolean dialogState = (app.cdmaOtaScreenState.otaScreenState
164e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                        == OtaUtils.CdmaOtaScreenState.OtaScreenState
165e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                        .OTA_STATUS_SUCCESS_FAILURE_DLG);
166e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                boolean isOtaCallActive = false;
167e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
1687c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                // TODO: Need cleaner way to check if OTA is active.
1697c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                // Also, this check seems to be broken in one obscure case: if
1707c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                // you interrupt an OTASP call by pressing Back then Skip,
1717c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                // otaScreenState somehow gets left in either PROGRESS or
1727c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                // LISTENING.
173e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                if ((app.cdmaOtaScreenState.otaScreenState
174e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                        == OtaUtils.CdmaOtaScreenState.OtaScreenState.OTA_STATUS_PROGRESS)
175e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                        || (app.cdmaOtaScreenState.otaScreenState
176e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                        == OtaUtils.CdmaOtaScreenState.OtaScreenState.OTA_STATUS_LISTENING)) {
177e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                    isOtaCallActive = true;
178e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                }
179e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
180e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                if (activateState || dialogState) {
1817c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    // The OTASP sequence is active, but either (1) the call
1827c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    // hasn't started yet, or (2) the call has ended and we're
1837c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    // showing the success/failure screen.  In either of these
1847c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    // cases it's OK to make a new outgoing call, but we need
1857c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    // to take down any OTASP-related UI first.
186e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                    if (dialogState) app.dismissOtaDialogs();
187e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                    app.clearOtaState();
188e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                    app.clearInCallScreenMode();
189e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                } else if (isOtaCallActive) {
1907c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    // The actual OTASP call is active.  Don't allow new
1917c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    // outgoing calls at all from this state.
1927c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    Log.w(TAG, "OTASP call is active: disallowing a new outgoing call.");
193e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                    return;
194e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                }
195e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            }
196e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
197e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            if (number == null) {
1986b0efb615a5b1a65984192384c88965fa7dd06a0David Brown                if (DBG) Log.v(TAG, "CALL cancelled (null number), returning...");
199e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                return;
2008343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            } else if (TelephonyCapabilities.supportsOtasp(app.phone)
201b0f85b4a78abead921c363f9c8e247d5bdd20c74Wink Saville                    && (app.phone.getState() != PhoneConstants.State.IDLE)
2028343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                    && (app.phone.isOtaSpNumber(number))) {
2036b0efb615a5b1a65984192384c88965fa7dd06a0David Brown                if (DBG) Log.v(TAG, "Call is active, a 2nd OTA call cancelled -- returning.");
204e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                return;
205a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            } else if (PhoneNumberUtils.isPotentialLocalEmergencyNumber(number, context)) {
206a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                // Just like 3rd-party apps aren't allowed to place emergency
207a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                // calls via the ACTION_CALL intent, we also don't allow 3rd
208a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                // party apps to use the NEW_OUTGOING_CALL broadcast to rewrite
209a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                // an outgoing call into an emergency number.
210e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                Log.w(TAG, "Cannot modify outgoing call to emergency number " + number + ".");
211e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                return;
212e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            }
213e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
214e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            originalUri = intent.getStringExtra(
215e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                    OutgoingCallBroadcaster.EXTRA_ORIGINAL_URI);
216e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            if (originalUri == null) {
217e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                Log.e(TAG, "Intent is missing EXTRA_ORIGINAL_URI -- returning.");
218e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                return;
219e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            }
220e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
221e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            Uri uri = Uri.parse(originalUri);
222e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
2238ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // We already called convertKeypadLettersToDigits() and
2248ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // stripSeparators() way back in onCreate(), before we sent out the
2258ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // NEW_OUTGOING_CALL broadcast.  But we need to do it again here
2268ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // too, since the number might have been modified/rewritten during
2278ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // the broadcast (and may now contain letters or separators again.)
2288ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            number = PhoneNumberUtils.convertKeypadLettersToDigits(number);
2298ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            number = PhoneNumberUtils.stripSeparators(number);
2305a57f046c7acae9867e7e4700ceec9fb07eb0a78Chung-yih Wang
2318ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            if (DBG) Log.v(TAG, "doReceive: proceeding with call...");
232a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown            if (VDBG) Log.v(TAG, "- uri: " + uri);
233a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown            if (VDBG) Log.v(TAG, "- actual number to dial: '" + number + "'");
234e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
2358ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            startSipCallOptionHandler(context, intent, uri, number);
2361e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        }
2371e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang    }
238e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
2398ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown    /**
2408ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * Launch the SipCallOptionHandler, which is the next step(*) in the
2418ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * outgoing-call sequence after the outgoing call broadcast is
2428ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * complete.
2438ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *
2448ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * (*) We now know exactly what phone number we need to dial, so the next
2458ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *     step is for the SipCallOptionHandler to decide which Phone type (SIP
2468ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *     or PSTN) should be used.  (Depending on the user's preferences, this
2478ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *     decision may also involve popping up a dialog to ask the user to
2488ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *     choose what type of call this should be.)
2498ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *
2508ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * @param context used for the startActivity() call
2518ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *
2528ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * @param intent the intent from the previous step of the outgoing-call
2538ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   sequence.  Normally this will be the NEW_OUTGOING_CALL broadcast intent
2548ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   that came in to the OutgoingCallReceiver, although it can also be the
2558ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   original ACTION_CALL intent that started the whole sequence (in cases
2568ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   where we don't do the NEW_OUTGOING_CALL broadcast at all, like for
2578ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   emergency numbers or SIP addresses).
2588ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *
2598ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * @param uri the data URI from the original CALL intent, presumably either
2608ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   a tel: or sip: URI.  For tel: URIs, note that the scheme-specific part
2618ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   does *not* necessarily have separators and keypad letters stripped (so
2628ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   we might see URIs like "tel:(650)%20555-1234" or "tel:1-800-GOOG-411"
2638ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   here.)
2648ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *
2658ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * @param number the actual number (or SIP address) to dial.  This is
2668ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   guaranteed to be either a PSTN phone number with separators stripped
2678ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   out and keypad letters converted to digits (like "16505551234"), or a
2688ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   raw SIP address (like "user@example.com").
2698ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     */
2708ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown    private void startSipCallOptionHandler(Context context, Intent intent,
2711e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang            Uri uri, String number) {
272a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown        if (VDBG) {
273a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown            Log.i(TAG, "startSipCallOptionHandler...");
274a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown            Log.i(TAG, "- intent: " + intent);
275a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown            Log.i(TAG, "- uri: " + uri);
276a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown            Log.i(TAG, "- number: " + number);
277a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown        }
27875e3711d82d0c98444f6c438437cad41d862fca6David Brown
27975e3711d82d0c98444f6c438437cad41d862fca6David Brown        // Create a copy of the original CALL intent that started the whole
28075e3711d82d0c98444f6c438437cad41d862fca6David Brown        // outgoing-call sequence.  This intent will ultimately be passed to
28175e3711d82d0c98444f6c438437cad41d862fca6David Brown        // CallController.placeCall() after the SipCallOptionHandler step.
28275e3711d82d0c98444f6c438437cad41d862fca6David Brown
2831e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        Intent newIntent = new Intent(Intent.ACTION_CALL, uri);
2848ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown        newIntent.putExtra(EXTRA_ACTUAL_NUMBER_TO_DIAL, number);
2851e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        PhoneUtils.checkAndCopyPhoneProviderExtras(intent, newIntent);
286e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
28775e3711d82d0c98444f6c438437cad41d862fca6David Brown        // Finally, launch the SipCallOptionHandler, with the copy of the
28875e3711d82d0c98444f6c438437cad41d862fca6David Brown        // original CALL intent stashed away in the EXTRA_NEW_CALL_INTENT
28975e3711d82d0c98444f6c438437cad41d862fca6David Brown        // extra.
2902587d9c6437b680911e252efecc73788e876de76Chung-yih Wang
29175e3711d82d0c98444f6c438437cad41d862fca6David Brown        Intent selectPhoneIntent = new Intent(ACTION_SIP_SELECT_PHONE, uri);
2921e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        selectPhoneIntent.setClass(context, SipCallOptionHandler.class);
2931e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        selectPhoneIntent.putExtra(EXTRA_NEW_CALL_INTENT, newIntent);
2941e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        selectPhoneIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
295ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa        if (DBG) {
296ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            Log.v(TAG, "startSipCallOptionHandler(): " +
297ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa                    "calling startActivity: " + selectPhoneIntent);
298ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa        }
2991e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        context.startActivity(selectPhoneIntent);
3008ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown        // ...and see SipCallOptionHandler.onCreate() for the next step of the sequence.
301e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn    }
302008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman
303ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    /**
304ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * This method is the single point of entry for the CALL intent, which is used (by built-in
305ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * apps like Contacts / Dialer, as well as 3rd-party apps) to initiate an outgoing voice call.
306ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *
307ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *
308ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     */
309b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    @Override
310b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    protected void onCreate(Bundle icicle) {
311b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        super.onCreate(icicle);
312ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa        setContentView(R.layout.outgoing_call_broadcaster);
313ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa        mWaitingSpinner = (ProgressBar) findViewById(R.id.spinner);
3146c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
315b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Intent intent = getIntent();
316ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa        if (DBG) {
317ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            final Configuration configuration = getResources().getConfiguration();
318ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            Log.v(TAG, "onCreate: this = " + this + ", icicle = " + icicle);
319ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            Log.v(TAG, " - getIntent() = " + intent);
320ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            Log.v(TAG, " - configuration = " + configuration);
321ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa        }
3227291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown
3237291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown        if (icicle != null) {
3247291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // A non-null icicle means that this activity is being
3257291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // re-initialized after previously being shut down.
3267291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            //
3277291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // In practice this happens very rarely (because the lifetime
3287291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // of this activity is so short!), but it *can* happen if the
3297291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // framework detects a configuration change at exactly the
3307291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // right moment; see bug 2202413.
3317291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            //
3327291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // In this case, do nothing.  Our onCreate() method has already
3337291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // run once (with icicle==null the first time), which means
3347291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // that the NEW_OUTGOING_CALL broadcast for this new call has
3357291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // already been sent.
3367291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            Log.i(TAG, "onCreate: non-null icicle!  "
3377291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown                  + "Bailing out, not sending NEW_OUTGOING_CALL broadcast...");
3387291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown
3397291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // No need to finish() here, since the OutgoingCallReceiver from
3407291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // our original instance will do that.  (It'll actually call
3417291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // finish() on our original instance, which apparently works fine
3427291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // even though the ActivityManager has already shut that instance
3437291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // down.  And note that if we *do* call finish() here, that just
3447291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // results in an "ActivityManager: Duplicate finish request"
3457291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // warning when the OutgoingCallReceiver runs.)
3467291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown
3477291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            return;
3487291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown        }
349b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
3500ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa        processIntent(intent);
3510ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa
3520ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa        // isFinishing() return false when 1. broadcast is still ongoing, or 2. dialog is being
3530ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa        // shown. Otherwise finish() is called inside processIntent(), is isFinishing() here will
3540ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa        // return true.
3550ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa        if (DBG) Log.v(TAG, "At the end of onCreate(). isFinishing(): " + isFinishing());
356ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    }
357ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa
358ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    /**
3590ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa     * Interprets a given Intent and starts something relevant to the Intent.
360ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *
361ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * This method will handle three kinds of actions:
362ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *
363ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * - CALL (action for usual outgoing voice calls)
364ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * - CALL_PRIVILEGED (can come from built-in apps like contacts / voice dialer / bluetooth)
365ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * - CALL_EMERGENCY (from the EmergencyDialer that's reachable from the lockscreen.)
366ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *
367ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * The exact behavior depends on the intent's data:
368ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *
369ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * - The most typical is a tel: URI, which we handle by starting the
370ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *   NEW_OUTGOING_CALL broadcast.  That broadcast eventually triggers
371ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *   the sequence OutgoingCallReceiver -> SipCallOptionHandler ->
372ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *   InCallScreen.
373ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *
374ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * - Or, with a sip: URI we skip the NEW_OUTGOING_CALL broadcast and
375ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *   go directly to SipCallOptionHandler, which then leads to the
376ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *   InCallScreen.
377ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *
378ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * - voicemail: URIs take the same path as regular tel: URIs.
379ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *
380ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * Other special cases:
381ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *
382ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * - Outgoing calls are totally disallowed on non-voice-capable
383ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *   devices (see handleNonVoiceCapable()).
384ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *
385ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * - A CALL intent with the EXTRA_SEND_EMPTY_FLASH extra (and
386ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *   presumably no data at all) means "send an empty flash" (which
387ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *   is only meaningful on CDMA devices while a call is already
388ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *   active.)
389ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     *
390ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     */
3910ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa    private void processIntent(Intent intent) {
3920ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa        if (DBG) {
3930ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa            Log.v(TAG, "processIntent() = " + intent + ", thread: " + Thread.currentThread());
3940ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa        }
395ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa        final Configuration configuration = getResources().getConfiguration();
396ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa
3976c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // Outgoing phone calls are only allowed on "voice-capable" devices.
398a1a9601840e50e18ff8ca4be9b888e592287577bDianne Hackborn        if (!PhoneGlobals.sVoiceCapable) {
399ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            Log.i(TAG, "This device is detected as non-voice-capable device.");
4000ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa            handleNonVoiceCapable(intent);
4010ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa            return;
4026c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        }
4036c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
404b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String action = intent.getAction();
405b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String number = PhoneNumberUtils.getNumberFromIntent(intent, this);
4068343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        // Check the number, don't convert for sip uri
4078343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        // TODO put uriNumber under PhoneNumberUtils
408b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (number != null) {
4098343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            if (!PhoneNumberUtils.isUriNumber(number)) {
4108343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                number = PhoneNumberUtils.convertKeypadLettersToDigits(number);
4118343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                number = PhoneNumberUtils.stripSeparators(number);
4128343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            }
413bd3132083f51f3e056134372720d73118cc5467aDaisuke Miyakawa        } else {
414bd3132083f51f3e056134372720d73118cc5467aDaisuke Miyakawa            Log.w(TAG, "The number obtained from Intent is null.");
415b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
416b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
417f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn        AppOpsManager appOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE);
418f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn        int launchedFromUid;
419f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn        String launchedFromPackage;
420f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn        try {
421f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn            launchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
422f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn                    getActivityToken());
423f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn            launchedFromPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
424f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn                    getActivityToken());
425f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn        } catch (RemoteException e) {
426f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn            launchedFromUid = -1;
427f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn            launchedFromPackage = null;
428f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn        }
429f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn        if (appOps.noteOp(AppOpsManager.OP_CALL_PHONE, launchedFromUid, launchedFromPackage)
430f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn                != AppOpsManager.MODE_ALLOWED) {
431f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn            Log.w(TAG, "Rejecting call from uid " + launchedFromUid + " package "
432f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn                    + launchedFromPackage);
433f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn            finish();
434f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn            return;
435f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn        }
436f88319b602881a0a67d80262b9842fbf42070ae3Dianne Hackborn
437a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // If true, this flag will indicate that the current call is a special kind
438a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // of call (most likely an emergency number) that 3rd parties aren't allowed
439a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // to intercept or affect in any way.  (In that case, we start the call
440a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // immediately rather than going through the NEW_OUTGOING_CALL sequence.)
441b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        boolean callNow;
442b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
443b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (getClass().getName().equals(intent.getComponent().getClassName())) {
444b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // If we were launched directly from the OutgoingCallBroadcaster,
445b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // not one of its more privileged aliases, then make sure that
446b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // only the non-privileged actions are allowed.
447b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (!Intent.ACTION_CALL.equals(intent.getAction())) {
448b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                Log.w(TAG, "Attempt to deliver non-CALL action; forcing to CALL");
449b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                intent.setAction(Intent.ACTION_CALL);
450b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
451b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
4525398ca30f57b928c2dd9bf175c5e083726279494Nicolas Catania
453a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // Check whether or not this is an emergency number, in order to
454a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // enforce the restriction that only the CALL_PRIVILEGED and
455a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // CALL_EMERGENCY intents are allowed to make emergency calls.
456a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        //
457a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // (Note that the ACTION_CALL check below depends on the result of
458a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // isPotentialLocalEmergencyNumber() rather than just plain
459a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // isLocalEmergencyNumber(), to be 100% certain that we *don't*
460a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // allow 3rd party apps to make emergency calls by passing in an
461a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // "invalid" number like "9111234" that isn't technically an
462a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // emergency number but might still result in an emergency call
463a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // with some networks.)
464a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        final boolean isExactEmergencyNumber =
465a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                (number != null) && PhoneNumberUtils.isLocalEmergencyNumber(number, this);
466a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        final boolean isPotentialEmergencyNumber =
467a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                (number != null) && PhoneNumberUtils.isPotentialLocalEmergencyNumber(number, this);
468a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        if (VDBG) {
469ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            Log.v(TAG, " - Checking restrictions for number '" + number + "':");
470ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            Log.v(TAG, "     isExactEmergencyNumber     = " + isExactEmergencyNumber);
471ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            Log.v(TAG, "     isPotentialEmergencyNumber = " + isPotentialEmergencyNumber);
472a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        }
473a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown
474b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /* Change CALL_PRIVILEGED into CALL or CALL_EMERGENCY as needed. */
475e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania        // TODO: This code is redundant with some code in InCallScreen: refactor.
476b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (Intent.ACTION_CALL_PRIVILEGED.equals(action)) {
477a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            // We're handling a CALL_PRIVILEGED intent, so we know this request came
478a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            // from a trusted source (like the built-in dialer.)  So even a number
479a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            // that's *potentially* an emergency number can safely be promoted to
480a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            // CALL_EMERGENCY (since we *should* allow you to dial "91112345" from
481a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            // the dialer if you really want to.)
482bd3132083f51f3e056134372720d73118cc5467aDaisuke Miyakawa            if (isPotentialEmergencyNumber) {
483bd3132083f51f3e056134372720d73118cc5467aDaisuke Miyakawa                Log.i(TAG, "ACTION_CALL_PRIVILEGED is used while the number is a potential"
484bd3132083f51f3e056134372720d73118cc5467aDaisuke Miyakawa                        + " emergency number. Use ACTION_CALL_EMERGENCY as an action instead.");
485bd3132083f51f3e056134372720d73118cc5467aDaisuke Miyakawa                action = Intent.ACTION_CALL_EMERGENCY;
486bd3132083f51f3e056134372720d73118cc5467aDaisuke Miyakawa            } else {
487bd3132083f51f3e056134372720d73118cc5467aDaisuke Miyakawa                action = Intent.ACTION_CALL;
488bd3132083f51f3e056134372720d73118cc5467aDaisuke Miyakawa            }
489ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            if (DBG) Log.v(TAG, " - updating action from CALL_PRIVILEGED to " + action);
490b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            intent.setAction(action);
491b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
492b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
493b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (Intent.ACTION_CALL.equals(action)) {
494a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            if (isPotentialEmergencyNumber) {
495a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                Log.w(TAG, "Cannot call potential emergency number '" + number
496a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                        + "' with CALL Intent " + intent + ".");
497a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                Log.i(TAG, "Launching default dialer instead...");
498e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania
499e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                Intent invokeFrameworkDialer = new Intent();
500e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania
501e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                // TwelveKeyDialer is in a tab so we really want
502e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                // DialtactsActivity.  Build the intent 'manually' to
503e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                // use the java resolver to find the dialer class (as
504e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                // opposed to a Context which look up known android
505e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                // packages only)
506d404e2b0d04af7deaa8a15ae6c852995ec602fc2Chiao Cheng                invokeFrameworkDialer.setClassName("com.android.dialer",
507d404e2b0d04af7deaa8a15ae6c852995ec602fc2Chiao Cheng                                                   "com.android.dialer.DialtactsActivity");
508e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                invokeFrameworkDialer.setAction(Intent.ACTION_DIAL);
509e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                invokeFrameworkDialer.setData(intent.getData());
5106b0efb615a5b1a65984192384c88965fa7dd06a0David Brown
5116b0efb615a5b1a65984192384c88965fa7dd06a0David Brown                if (DBG) Log.v(TAG, "onCreate(): calling startActivity for Dialer: "
5126b0efb615a5b1a65984192384c88965fa7dd06a0David Brown                               + invokeFrameworkDialer);
5130ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa                startActivity(invokeFrameworkDialer);
5140ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa                finish();
5150ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa                return;
516b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
517b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            callNow = false;
518b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {
519325cc2ced6f1ff5fb1708abfcc5e9c73ac0cd962David Brown            // ACTION_CALL_EMERGENCY case: this is either a CALL_PRIVILEGED
520325cc2ced6f1ff5fb1708abfcc5e9c73ac0cd962David Brown            // intent that we just turned into a CALL_EMERGENCY intent (see
521325cc2ced6f1ff5fb1708abfcc5e9c73ac0cd962David Brown            // above), or else it really is an CALL_EMERGENCY intent that
522325cc2ced6f1ff5fb1708abfcc5e9c73ac0cd962David Brown            // came directly from some other app (e.g. the EmergencyDialer
523325cc2ced6f1ff5fb1708abfcc5e9c73ac0cd962David Brown            // activity built in to the Phone app.)
524a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            // Make sure it's at least *possible* that this is really an
525a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            // emergency number.
526a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            if (!isPotentialEmergencyNumber) {
527a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                Log.w(TAG, "Cannot call non-potential-emergency number " + number
5280ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa                        + " with EMERGENCY_CALL Intent " + intent + "."
5290ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa                        + " Finish the Activity immediately.");
5300ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa                finish();
5310ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa                return;
532b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
533b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            callNow = true;
534b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
5350ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa            Log.e(TAG, "Unhandled Intent " + intent + ". Finish the Activity immediately.");
5360ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa            finish();
5370ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa            return;
538b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
539b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
540b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Make sure the screen is turned on.  This is probably the right
541b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // thing to do, and more importantly it works around an issue in the
542b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // activity manager where we will not launch activities consistently
543b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // when the screen is off (since it is trying to keep them paused
544b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // and has...  issues).
545b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //
546b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Also, this ensures the device stays awake while doing the following
547b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // broadcast; technically we should be holding a wake lock here
548b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // as well.
549a1a9601840e50e18ff8ca4be9b888e592287577bDianne Hackborn        PhoneGlobals.getInstance().wakeUpScreen();
5505398ca30f57b928c2dd9bf175c5e083726279494Nicolas Catania
551b1545c869ff7fa76ce3c3256b23e1b2b4411f483Daisuke Miyakawa        // If number is null, we're probably trying to call a non-existent voicemail number,
552b1545c869ff7fa76ce3c3256b23e1b2b4411f483Daisuke Miyakawa        // send an empty flash or something else is fishy.  Whatever the problem, there's no
553b1545c869ff7fa76ce3c3256b23e1b2b4411f483Daisuke Miyakawa        // number, so there's no point in allowing apps to modify the number.
554bd3132083f51f3e056134372720d73118cc5467aDaisuke Miyakawa        if (TextUtils.isEmpty(number)) {
555008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman            if (intent.getBooleanExtra(EXTRA_SEND_EMPTY_FLASH, false)) {
5567291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown                Log.i(TAG, "onCreate: SEND_EMPTY_FLASH...");
557a1a9601840e50e18ff8ca4be9b888e592287577bDianne Hackborn                PhoneUtils.sendEmptyFlash(PhoneGlobals.getPhone());
5580ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa                finish();
5590ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa                return;
560008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman            } else {
5617291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown                Log.i(TAG, "onCreate: null or empty number, setting callNow=true...");
562008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman                callNow = true;
563008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman            }
564008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman        }
565b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
566b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (callNow) {
56758e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // This is a special kind of call (most likely an emergency number)
56858e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // that 3rd parties aren't allowed to intercept or affect in any way.
56958e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // So initiate the outgoing call immediately.
57058e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown
571bd3132083f51f3e056134372720d73118cc5467aDaisuke Miyakawa            Log.i(TAG, "onCreate(): callNow case! Calling placeCall(): " + intent);
57258e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown
57358e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // Initiate the outgoing call, and simultaneously launch the
57458e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // InCallScreen to display the in-call UI:
575a1a9601840e50e18ff8ca4be9b888e592287577bDianne Hackborn            PhoneGlobals.getInstance().callController.placeCall(intent);
57658e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown
57758e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // Note we do *not* "return" here, but instead continue and
57858e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // send the ACTION_NEW_OUTGOING_CALL broadcast like for any
57958e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // other outgoing call.  (But when the broadcast finally
58058e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // reaches the OutgoingCallReceiver, we'll know not to
58158e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // initiate the call again because of the presence of the
58258e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // EXTRA_ALREADY_CALLED extra.)
583b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
584b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
585919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa        // Remember the call origin so that users will be able to see an appropriate screen
586919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa        // after the phone call. This should affect both phone calls and SIP calls.
587a1a9601840e50e18ff8ca4be9b888e592287577bDianne Hackborn        final String callOrigin = intent.getStringExtra(PhoneGlobals.EXTRA_CALL_ORIGIN);
588919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa        if (callOrigin != null) {
589ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            if (DBG) Log.v(TAG, " - Call origin is passed (" + callOrigin + ")");
590a1a9601840e50e18ff8ca4be9b888e592287577bDianne Hackborn            PhoneGlobals.getInstance().setLatestActiveCallOrigin(callOrigin);
591919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa        } else {
592ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa            if (DBG) Log.v(TAG, " - Call origin is not passed. Reset current one.");
593a1a9601840e50e18ff8ca4be9b888e592287577bDianne Hackborn            PhoneGlobals.getInstance().resetLatestActiveCallOrigin();
594919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa        }
595919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa
5961e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // For now, SIP calls will be processed directly without a
5971e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // NEW_OUTGOING_CALL broadcast.
5981e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        //
5991e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // TODO: In the future, though, 3rd party apps *should* be allowed to
6001e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // intercept outgoing calls to SIP addresses as well.  To do this, we should
6011e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // (1) update the NEW_OUTGOING_CALL intent documentation to explain this
6021e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // case, and (2) pass the outgoing SIP address by *not* overloading the
6031e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // EXTRA_PHONE_NUMBER extra, but instead using a new separate extra to hold
6041e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // the outgoing SIP address.  (Be sure to document whether it's a URI or just
6051e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // a plain address, whether it could be a tel: URI, etc.)
6061e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        Uri uri = intent.getData();
6071e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        String scheme = uri.getScheme();
608ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa        if (Constants.SCHEME_SIP.equals(scheme) || PhoneNumberUtils.isUriNumber(number)) {
6090ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa            Log.i(TAG, "The requested number was detected as SIP call.");
6100ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa            startSipCallOptionHandler(this, intent, uri, number);
6110ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa            finish();
6120ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa            return;
61358e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown
61458e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // TODO: if there's ever a way for SIP calls to trigger a
61558e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // "callNow=true" case (see above), we'll need to handle that
61658e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // case here too (most likely by just doing nothing at all.)
6171e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        }
6181e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang
619b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
6205398ca30f57b928c2dd9bf175c5e083726279494Nicolas Catania        if (number != null) {
6215398ca30f57b928c2dd9bf175c5e083726279494Nicolas Catania            broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
6225398ca30f57b928c2dd9bf175c5e083726279494Nicolas Catania        }
623d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania        PhoneUtils.checkAndCopyPhoneProviderExtras(intent, broadcastIntent);
624b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        broadcastIntent.putExtra(EXTRA_ALREADY_CALLED, callNow);
6251e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        broadcastIntent.putExtra(EXTRA_ORIGINAL_URI, uri.toString());
626b967bf2d5ecbe57e3fe2d9d9389b203582b73fbfDaisuke Miyakawa        // Need to raise foreground in-call UI as soon as possible while allowing 3rd party app
627b967bf2d5ecbe57e3fe2d9d9389b203582b73fbfDaisuke Miyakawa        // to intercept the outgoing call.
628b967bf2d5ecbe57e3fe2d9d9389b203582b73fbfDaisuke Miyakawa        broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
629ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa        if (DBG) Log.v(TAG, " - Broadcasting intent: " + broadcastIntent + ".");
63008ad9a53367c93ab76dbc1d2c7a58681a6533cf8Daisuke Miyakawa
63108ad9a53367c93ab76dbc1d2c7a58681a6533cf8Daisuke Miyakawa        // Set a timer so that we can prepare for unexpected delay introduced by the broadcast.
63208ad9a53367c93ab76dbc1d2c7a58681a6533cf8Daisuke Miyakawa        // If it takes too much time, the timer will show "waiting" spinner.
63308ad9a53367c93ab76dbc1d2c7a58681a6533cf8Daisuke Miyakawa        // This message will be removed when OutgoingCallReceiver#onReceive() is called before the
63408ad9a53367c93ab76dbc1d2c7a58681a6533cf8Daisuke Miyakawa        // timeout.
63508ad9a53367c93ab76dbc1d2c7a58681a6533cf8Daisuke Miyakawa        mHandler.sendEmptyMessageDelayed(EVENT_OUTGOING_CALL_TIMEOUT,
63608ad9a53367c93ab76dbc1d2c7a58681a6533cf8Daisuke Miyakawa                OUTGOING_CALL_TIMEOUT_THRESHOLD);
63791177a70c9024522c1d0d3ac570124998f09647aDianne Hackborn        sendOrderedBroadcastAsUser(broadcastIntent, UserHandle.OWNER,
63891177a70c9024522c1d0d3ac570124998f09647aDianne Hackborn                PERMISSION, new OutgoingCallReceiver(),
6390ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa                null,  // scheduler
6400ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa                Activity.RESULT_OK,  // initialCode
6410ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa                number,  // initialData: initial value for the result data
6420ab033df74e18e0775929422db5f4fce204ec22aDaisuke Miyakawa                null);  // initialExtras
643b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
6447291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown
6456c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    @Override
6466c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    protected void onStop() {
6476c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // Clean up (and dismiss if necessary) any managed dialogs.
6486c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
6496c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // We don't do this in onPause() since we can be paused/resumed
6506c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // due to orientation changes (in which case we don't want to
6516c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // disturb the dialog), but we *do* need it here in onStop() to be
6526c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // sure we clean up if the user hits HOME while the dialog is up.
6536c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
6546c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // Note it's safe to call removeDialog() even if there's no dialog
6556c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // associated with that ID.
6566c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        removeDialog(DIALOG_NOT_VOICE_CAPABLE);
6576c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
6586c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        super.onStop();
6596c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    }
6606c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
6616c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    /**
6626c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown     * Handle the specified CALL or CALL_* intent on a non-voice-capable
6636c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown     * device.
6646c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown     *
6656c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown     * This method may launch a different intent (if there's some useful
6666c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown     * alternative action to take), or otherwise display an error dialog,
6676c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown     * and in either case will finish() the current activity when done.
6686c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown     */
6696c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    private void handleNonVoiceCapable(Intent intent) {
6706c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        if (DBG) Log.v(TAG, "handleNonVoiceCapable: handling " + intent
6716c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                       + " on non-voice-capable device...");
6726c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        String action = intent.getAction();
6736c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        Uri uri = intent.getData();
6746c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        String scheme = uri.getScheme();
6756c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
6766c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // Handle one special case: If this is a regular CALL to a tel: URI,
6776c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // bring up a UI letting you do something useful with the phone number
6786c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // (like "Add to contacts" if it isn't a contact yet.)
6796c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
6806c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // This UI is provided by the contacts app in response to a DIAL
6816c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // intent, so we bring it up here by demoting this CALL to a DIAL and
6826c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // relaunching.
6836c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
6846c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // TODO: it's strange and unintuitive to manually launch a DIAL intent
6856c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // to do this; it would be cleaner to have some shared UI component
6866c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // that we could bring up directly.  (But for now at least, since both
6876c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // Contacts and Phone are built-in apps, this implementation is fine.)
6886c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
68965454c803eb305c4740885ad4995a871b034a58aDavid Brown        if (Intent.ACTION_CALL.equals(action) && (Constants.SCHEME_TEL.equals(scheme))) {
6906c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            Intent newIntent = new Intent(Intent.ACTION_DIAL, uri);
6916c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            if (DBG) Log.v(TAG, "- relaunching as a DIAL intent: " + newIntent);
6926c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            startActivity(newIntent);
6936c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            finish();
6946c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            return;
6956c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        }
6966c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
6976c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // In all other cases, just show a generic "voice calling not
6986c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // supported" dialog.
6996c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        showDialog(DIALOG_NOT_VOICE_CAPABLE);
7006c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // ...and we'll eventually finish() when the user dismisses
7016c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // or cancels the dialog.
7026c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    }
7036c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
7046c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    @Override
7056c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    protected Dialog onCreateDialog(int id) {
7066c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        Dialog dialog;
7076c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        switch(id) {
7086c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            case DIALOG_NOT_VOICE_CAPABLE:
7096c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                dialog = new AlertDialog.Builder(this)
7106c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                        .setTitle(R.string.not_voice_capable)
71150480073bf2394d5b065084f46b2223ab90fb7dcDaisuke Miyakawa                        .setIconAttribute(android.R.attr.alertDialogIcon)
7126c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                        .setPositiveButton(android.R.string.ok, this)
7136c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                        .setOnCancelListener(this)
7146c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                        .create();
7156c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                break;
7166c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            default:
7176c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                Log.w(TAG, "onCreateDialog: unexpected ID " + id);
7186c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                dialog = null;
7196c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                break;
7206c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        }
7216c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        return dialog;
7226c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    }
7236c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
724ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    /** DialogInterface.OnClickListener implementation */
725ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    @Override
7266c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    public void onClick(DialogInterface dialog, int id) {
7276c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // DIALOG_NOT_VOICE_CAPABLE is the only dialog we ever use (so far
7286c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // at least), and its only button is "OK".
7296c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        finish();
7306c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    }
7316c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
732ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    /** DialogInterface.OnCancelListener implementation */
733ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    @Override
7346c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    public void onCancel(DialogInterface dialog) {
7356c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // DIALOG_NOT_VOICE_CAPABLE is the only dialog we ever use (so far
7366c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // at least), and canceling it is just like hitting "OK".
7376c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        finish();
7386c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    }
7396c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
740ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa    /**
741ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * Implement onConfigurationChanged() purely for debugging purposes,
742ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * to make sure that the android:configChanges element in our manifest
743ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     * is working properly.
744ac9a757e713579e7ae5728e22e884459682cbd50Daisuke Miyakawa     */
7457291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown    @Override
7467291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown    public void onConfigurationChanged(Configuration newConfig) {
7477291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown        super.onConfigurationChanged(newConfig);
7487291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown        if (DBG) Log.v(TAG, "onConfigurationChanged: newConfig = " + newConfig);
7497291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown    }
750b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project}
751