OutgoingCallBroadcaster.java revision 50480073bf2394d5b065084f46b2223ab90fb7dc
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;
206c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brownimport android.app.AlertDialog;
216c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brownimport android.app.Dialog;
22b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.BroadcastReceiver;
23b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Context;
246c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brownimport android.content.DialogInterface;
25b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Intent;
267291a106eb69b365de60a9452c5fc31828e2db8eDavid Brownimport android.content.res.Configuration;
27b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.net.Uri;
28b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Bundle;
296b0efb615a5b1a65984192384c88965fa7dd06a0David Brownimport android.os.SystemProperties;
30b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.telephony.PhoneNumberUtils;
31008791ca2a9a1406c2a9f7b39c794104d151b898Paul Bermanimport android.text.TextUtils;
32b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.util.Log;
33b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
346b0efb615a5b1a65984192384c88965fa7dd06a0David Brownimport com.android.internal.telephony.Phone;
356b0efb615a5b1a65984192384c88965fa7dd06a0David Brown
361ca2b2b333a7c22b728d648d3592ee064762dd00Shaopeng Jia
37b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/**
386b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * OutgoingCallBroadcaster receives CALL and CALL_PRIVILEGED Intents, and
396b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * broadcasts the ACTION_NEW_OUTGOING_CALL intent which allows other
406b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * applications to monitor, redirect, or prevent the outgoing call.
416b0efb615a5b1a65984192384c88965fa7dd06a0David Brown
426b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * After the other applications have had a chance to see the
436b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * ACTION_NEW_OUTGOING_CALL intent, it finally reaches the
446b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * {@link OutgoingCallReceiver}, which passes the (possibly modified)
458ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown * intent on to the {@link SipCallOptionHandler}, which will
468ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown * ultimately start the call using the CallController.placeCall() API.
47b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project *
486b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * Emergency calls and calls where no number is present (like for a CDMA
496b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * "empty flash" or a nonexistent voicemail number) are exempt from being
506b0efb615a5b1a65984192384c88965fa7dd06a0David Brown * broadcast.
51b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */
526c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brownpublic class OutgoingCallBroadcaster extends Activity
536c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
54b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
55b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final String PERMISSION = android.Manifest.permission.PROCESS_OUTGOING_CALLS;
56b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    private static final String TAG = "OutgoingCallBroadcaster";
576b0efb615a5b1a65984192384c88965fa7dd06a0David Brown    private static final boolean DBG =
586b0efb615a5b1a65984192384c88965fa7dd06a0David Brown            (PhoneApp.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
59a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown    // Do not check in with VDBG = true, since that may write PII to the system log.
60a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown    private static final boolean VDBG = false;
61b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
6275e3711d82d0c98444f6c438437cad41d862fca6David Brown    public static final String ACTION_SIP_SELECT_PHONE = "com.android.phone.SIP_SELECT_PHONE";
63b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static final String EXTRA_ALREADY_CALLED = "android.phone.extra.ALREADY_CALLED";
64b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    public static final String EXTRA_ORIGINAL_URI = "android.phone.extra.ORIGINAL_URI";
652587d9c6437b680911e252efecc73788e876de76Chung-yih Wang    public static final String EXTRA_NEW_CALL_INTENT = "android.phone.extra.NEW_CALL_INTENT";
662587d9c6437b680911e252efecc73788e876de76Chung-yih Wang    public static final String EXTRA_SIP_PHONE_URI = "android.phone.extra.SIP_PHONE_URI";
678ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown    public static final String EXTRA_ACTUAL_NUMBER_TO_DIAL =
688ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            "android.phone.extra.ACTUAL_NUMBER_TO_DIAL";
69b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
70e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn    /**
71008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * Identifier for intent extra for sending an empty Flash message for
72008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * CDMA networks. This message is used by the network to simulate a
73008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * press/depress of the "hookswitch" of a landline phone. Aka "empty flash".
74008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     *
75008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * TODO: Receiving an intent extra to tell the phone to send this flash is a
76008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * temporary measure. To be replaced with an external ITelephony call in the future.
77008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * TODO: Keep in sync with the string defined in TwelveKeyDialer.java in Contacts app
78008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     * until this is replaced with the ITelephony API.
79008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman     */
80008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman    public static final String EXTRA_SEND_EMPTY_FLASH = "com.android.phone.extra.SEND_EMPTY_FLASH";
81008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman
826c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    // Dialog IDs
836c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    private static final int DIALOG_NOT_VOICE_CAPABLE = 1;
846c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
85008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman    /**
86e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn     * OutgoingCallReceiver finishes NEW_OUTGOING_CALL broadcasts, starting
87e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn     * the InCallScreen if the broadcast has not been canceled, possibly with
88e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn     * a modified phone number and optional provider info (uri + package name + remote views.)
89e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn     */
90e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn    public class OutgoingCallReceiver extends BroadcastReceiver {
91e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn        private static final String TAG = "OutgoingCallReceiver";
92e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
93e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn        public void onReceive(Context context, Intent intent) {
94e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            doReceive(context, intent);
95e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            finish();
96e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn        }
97008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman
98e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn        public void doReceive(Context context, Intent intent) {
996b0efb615a5b1a65984192384c88965fa7dd06a0David Brown            if (DBG) Log.v(TAG, "doReceive: " + intent);
1006b0efb615a5b1a65984192384c88965fa7dd06a0David Brown
101e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            boolean alreadyCalled;
102e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            String number;
103e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            String originalUri;
104e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
105e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            alreadyCalled = intent.getBooleanExtra(
106e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                    OutgoingCallBroadcaster.EXTRA_ALREADY_CALLED, false);
107e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            if (alreadyCalled) {
1086b0efb615a5b1a65984192384c88965fa7dd06a0David Brown                if (DBG) Log.v(TAG, "CALL already placed -- returning.");
109e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                return;
110e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            }
111e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
1128ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // Once the NEW_OUTGOING_CALL broadcast is finished, the resultData
1138ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // is used as the actual number to call. (If null, no call will be
1148ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // placed.)
1158ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown
116e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            number = getResultData();
117a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown            if (VDBG) Log.v(TAG, "- got number from resultData: '" + number + "'");
1188ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown
119e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            final PhoneApp app = PhoneApp.getInstance();
1208343169cc89621d46dce86449f5ee1ff5d3a4919John Wang
1217c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown            // OTASP-specific checks.
1227c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown            // TODO: This should probably all happen in
1237c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown            // OutgoingCallBroadcaster.onCreate(), since there's no reason to
1247c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown            // even bother with the NEW_OUTGOING_CALL broadcast if we're going
1257c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown            // to disallow the outgoing call anyway...
1268343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            if (TelephonyCapabilities.supportsOtasp(app.phone)) {
127e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                boolean activateState = (app.cdmaOtaScreenState.otaScreenState
128e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                        == OtaUtils.CdmaOtaScreenState.OtaScreenState.OTA_STATUS_ACTIVATION);
129e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                boolean dialogState = (app.cdmaOtaScreenState.otaScreenState
130e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                        == OtaUtils.CdmaOtaScreenState.OtaScreenState
131e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                        .OTA_STATUS_SUCCESS_FAILURE_DLG);
132e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                boolean isOtaCallActive = false;
133e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
1347c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                // TODO: Need cleaner way to check if OTA is active.
1357c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                // Also, this check seems to be broken in one obscure case: if
1367c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                // you interrupt an OTASP call by pressing Back then Skip,
1377c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                // otaScreenState somehow gets left in either PROGRESS or
1387c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                // LISTENING.
139e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                if ((app.cdmaOtaScreenState.otaScreenState
140e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                        == OtaUtils.CdmaOtaScreenState.OtaScreenState.OTA_STATUS_PROGRESS)
141e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                        || (app.cdmaOtaScreenState.otaScreenState
142e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                        == OtaUtils.CdmaOtaScreenState.OtaScreenState.OTA_STATUS_LISTENING)) {
143e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                    isOtaCallActive = true;
144e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                }
145e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
146e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                if (activateState || dialogState) {
1477c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    // The OTASP sequence is active, but either (1) the call
1487c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    // hasn't started yet, or (2) the call has ended and we're
1497c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    // showing the success/failure screen.  In either of these
1507c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    // cases it's OK to make a new outgoing call, but we need
1517c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    // to take down any OTASP-related UI first.
152e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                    if (dialogState) app.dismissOtaDialogs();
153e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                    app.clearOtaState();
154e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                    app.clearInCallScreenMode();
155e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                } else if (isOtaCallActive) {
1567c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    // The actual OTASP call is active.  Don't allow new
1577c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    // outgoing calls at all from this state.
1587c8cb32060a685b2f20c1e0cf181fc392be840e0David Brown                    Log.w(TAG, "OTASP call is active: disallowing a new outgoing call.");
159e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                    return;
160e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                }
161e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            }
162e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
163e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            if (number == null) {
1646b0efb615a5b1a65984192384c88965fa7dd06a0David Brown                if (DBG) Log.v(TAG, "CALL cancelled (null number), returning...");
165e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                return;
1668343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            } else if (TelephonyCapabilities.supportsOtasp(app.phone)
1678343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                    && (app.phone.getState() != Phone.State.IDLE)
1688343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                    && (app.phone.isOtaSpNumber(number))) {
1696b0efb615a5b1a65984192384c88965fa7dd06a0David Brown                if (DBG) Log.v(TAG, "Call is active, a 2nd OTA call cancelled -- returning.");
170e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                return;
171a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            } else if (PhoneNumberUtils.isPotentialLocalEmergencyNumber(number, context)) {
172a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                // Just like 3rd-party apps aren't allowed to place emergency
173a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                // calls via the ACTION_CALL intent, we also don't allow 3rd
174a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                // party apps to use the NEW_OUTGOING_CALL broadcast to rewrite
175a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                // an outgoing call into an emergency number.
176e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                Log.w(TAG, "Cannot modify outgoing call to emergency number " + number + ".");
177e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                return;
178e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            }
179e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
180e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            originalUri = intent.getStringExtra(
181e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                    OutgoingCallBroadcaster.EXTRA_ORIGINAL_URI);
182e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            if (originalUri == null) {
183e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                Log.e(TAG, "Intent is missing EXTRA_ORIGINAL_URI -- returning.");
184e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn                return;
185e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            }
186e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
187e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn            Uri uri = Uri.parse(originalUri);
188e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
1898ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // We already called convertKeypadLettersToDigits() and
1908ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // stripSeparators() way back in onCreate(), before we sent out the
1918ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // NEW_OUTGOING_CALL broadcast.  But we need to do it again here
1928ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // too, since the number might have been modified/rewritten during
1938ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            // the broadcast (and may now contain letters or separators again.)
1948ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            number = PhoneNumberUtils.convertKeypadLettersToDigits(number);
1958ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            number = PhoneNumberUtils.stripSeparators(number);
1965a57f046c7acae9867e7e4700ceec9fb07eb0a78Chung-yih Wang
1978ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            if (DBG) Log.v(TAG, "doReceive: proceeding with call...");
198a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown            if (VDBG) Log.v(TAG, "- uri: " + uri);
199a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown            if (VDBG) Log.v(TAG, "- actual number to dial: '" + number + "'");
200e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
2018ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            startSipCallOptionHandler(context, intent, uri, number);
2021e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        }
2031e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang    }
204e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
2058ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown    /**
2068ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * Launch the SipCallOptionHandler, which is the next step(*) in the
2078ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * outgoing-call sequence after the outgoing call broadcast is
2088ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * complete.
2098ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *
2108ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * (*) We now know exactly what phone number we need to dial, so the next
2118ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *     step is for the SipCallOptionHandler to decide which Phone type (SIP
2128ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *     or PSTN) should be used.  (Depending on the user's preferences, this
2138ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *     decision may also involve popping up a dialog to ask the user to
2148ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *     choose what type of call this should be.)
2158ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *
2168ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * @param context used for the startActivity() call
2178ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *
2188ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * @param intent the intent from the previous step of the outgoing-call
2198ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   sequence.  Normally this will be the NEW_OUTGOING_CALL broadcast intent
2208ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   that came in to the OutgoingCallReceiver, although it can also be the
2218ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   original ACTION_CALL intent that started the whole sequence (in cases
2228ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   where we don't do the NEW_OUTGOING_CALL broadcast at all, like for
2238ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   emergency numbers or SIP addresses).
2248ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *
2258ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * @param uri the data URI from the original CALL intent, presumably either
2268ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   a tel: or sip: URI.  For tel: URIs, note that the scheme-specific part
2278ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   does *not* necessarily have separators and keypad letters stripped (so
2288ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   we might see URIs like "tel:(650)%20555-1234" or "tel:1-800-GOOG-411"
2298ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   here.)
2308ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *
2318ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     * @param number the actual number (or SIP address) to dial.  This is
2328ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   guaranteed to be either a PSTN phone number with separators stripped
2338ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   out and keypad letters converted to digits (like "16505551234"), or a
2348ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     *   raw SIP address (like "user@example.com").
2358ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown     */
2368ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown    private void startSipCallOptionHandler(Context context, Intent intent,
2371e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang            Uri uri, String number) {
238a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown        if (VDBG) {
239a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown            Log.i(TAG, "startSipCallOptionHandler...");
240a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown            Log.i(TAG, "- intent: " + intent);
241a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown            Log.i(TAG, "- uri: " + uri);
242a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown            Log.i(TAG, "- number: " + number);
243a841177ae2676d3ad92f82f8d378bc4915f238c9David Brown        }
24475e3711d82d0c98444f6c438437cad41d862fca6David Brown
24575e3711d82d0c98444f6c438437cad41d862fca6David Brown        // Create a copy of the original CALL intent that started the whole
24675e3711d82d0c98444f6c438437cad41d862fca6David Brown        // outgoing-call sequence.  This intent will ultimately be passed to
24775e3711d82d0c98444f6c438437cad41d862fca6David Brown        // CallController.placeCall() after the SipCallOptionHandler step.
24875e3711d82d0c98444f6c438437cad41d862fca6David Brown
2491e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        Intent newIntent = new Intent(Intent.ACTION_CALL, uri);
2508ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown        newIntent.putExtra(EXTRA_ACTUAL_NUMBER_TO_DIAL, number);
2511e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        PhoneUtils.checkAndCopyPhoneProviderExtras(intent, newIntent);
252e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn
25375e3711d82d0c98444f6c438437cad41d862fca6David Brown        // Finally, launch the SipCallOptionHandler, with the copy of the
25475e3711d82d0c98444f6c438437cad41d862fca6David Brown        // original CALL intent stashed away in the EXTRA_NEW_CALL_INTENT
25575e3711d82d0c98444f6c438437cad41d862fca6David Brown        // extra.
2562587d9c6437b680911e252efecc73788e876de76Chung-yih Wang
25775e3711d82d0c98444f6c438437cad41d862fca6David Brown        Intent selectPhoneIntent = new Intent(ACTION_SIP_SELECT_PHONE, uri);
2581e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        selectPhoneIntent.setClass(context, SipCallOptionHandler.class);
2591e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        selectPhoneIntent.putExtra(EXTRA_NEW_CALL_INTENT, newIntent);
2601e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        selectPhoneIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2618ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown        if (DBG) Log.v(TAG, "startSipCallOptionHandler(): " +
2621e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang                "calling startActivity: " + selectPhoneIntent);
2631e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        context.startActivity(selectPhoneIntent);
2648ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown        // ...and see SipCallOptionHandler.onCreate() for the next step of the sequence.
265e118d10e688f3f98579253bc64de3c9422104350Dianne Hackborn    }
266008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman
267b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    @Override
268b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    protected void onCreate(Bundle icicle) {
269b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        super.onCreate(icicle);
270b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
2716c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // This method is the single point of entry for the CALL intent,
2726c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // which is used (by built-in apps like Contacts / Dialer, as well
2736c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // as 3rd-party apps) to initiate an outgoing voice call.
2746c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
2756c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // We also handle two related intents which are only used internally:
2766c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // CALL_PRIVILEGED (which can come from built-in apps like contacts /
2776c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // voice dialer / bluetooth), and CALL_EMERGENCY (from the
2786c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // EmergencyDialer that's reachable from the lockscreen.)
2796c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
2806c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // The exact behavior depends on the intent's data:
2816c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
2826c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // - The most typical is a tel: URI, which we handle by starting the
283b1545c869ff7fa76ce3c3256b23e1b2b4411f483Daisuke Miyakawa        //   NEW_OUTGOING_CALL broadcast.  That broadcast eventually triggers
2846c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //   the sequence OutgoingCallReceiver -> SipCallOptionHandler ->
2856c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //   InCallScreen.
2866c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
2876c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // - Or, with a sip: URI we skip the NEW_OUTGOING_CALL broadcast and
2886c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //   go directly to SipCallOptionHandler, which then leads to the
2896c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //   InCallScreen.
2906c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
2916c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // - voicemail: URIs take the same path as regular tel: URIs.
2926c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
2936c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // Other special cases:
2946c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
2956c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // - Outgoing calls are totally disallowed on non-voice-capable
2966c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //   devices (see handleNonVoiceCapable()).
2976c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
2986c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // - A CALL intent with the EXTRA_SEND_EMPTY_FLASH extra (and
2996c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //   presumably no data at all) means "send an empty flash" (which
3006c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //   is only meaningful on CDMA devices while a call is already
3016c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //   active.)
3026c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
303b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Intent intent = getIntent();
3047291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown        final Configuration configuration = getResources().getConfiguration();
3057291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown
3067291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown        if (DBG) Log.v(TAG, "onCreate: this = " + this + ", icicle = " + icicle);
3077291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown        if (DBG) Log.v(TAG, " - getIntent() = " + intent);
3087291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown        if (DBG) Log.v(TAG, " - configuration = " + configuration);
3097291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown
3107291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown        if (icicle != null) {
3117291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // A non-null icicle means that this activity is being
3127291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // re-initialized after previously being shut down.
3137291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            //
3147291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // In practice this happens very rarely (because the lifetime
3157291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // of this activity is so short!), but it *can* happen if the
3167291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // framework detects a configuration change at exactly the
3177291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // right moment; see bug 2202413.
3187291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            //
3197291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // In this case, do nothing.  Our onCreate() method has already
3207291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // run once (with icicle==null the first time), which means
3217291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // that the NEW_OUTGOING_CALL broadcast for this new call has
3227291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // already been sent.
3237291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            Log.i(TAG, "onCreate: non-null icicle!  "
3247291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown                  + "Bailing out, not sending NEW_OUTGOING_CALL broadcast...");
3257291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown
3267291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // No need to finish() here, since the OutgoingCallReceiver from
3277291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // our original instance will do that.  (It'll actually call
3287291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // finish() on our original instance, which apparently works fine
3297291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // even though the ActivityManager has already shut that instance
3307291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // down.  And note that if we *do* call finish() here, that just
3317291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // results in an "ActivityManager: Duplicate finish request"
3327291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            // warning when the OutgoingCallReceiver runs.)
3337291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown
3347291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown            return;
3357291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown        }
336b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
3376c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // Outgoing phone calls are only allowed on "voice-capable" devices.
3386c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        if (!PhoneApp.sVoiceCapable) {
3396c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            handleNonVoiceCapable(intent);
3406c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            // No need to finish() here; handleNonVoiceCapable() will do
3416c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            // that if necessary.
3426c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            return;
3436c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        }
3446c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
345b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String action = intent.getAction();
346b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        String number = PhoneNumberUtils.getNumberFromIntent(intent, this);
3478343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        // Check the number, don't convert for sip uri
3488343169cc89621d46dce86449f5ee1ff5d3a4919John Wang        // TODO put uriNumber under PhoneNumberUtils
349b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (number != null) {
3508343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            if (!PhoneNumberUtils.isUriNumber(number)) {
3518343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                number = PhoneNumberUtils.convertKeypadLettersToDigits(number);
3528343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                number = PhoneNumberUtils.stripSeparators(number);
3538343169cc89621d46dce86449f5ee1ff5d3a4919John Wang            }
354b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
355b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
356a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // If true, this flag will indicate that the current call is a special kind
357a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // of call (most likely an emergency number) that 3rd parties aren't allowed
358a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // to intercept or affect in any way.  (In that case, we start the call
359a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // immediately rather than going through the NEW_OUTGOING_CALL sequence.)
360b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        boolean callNow;
361b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
362b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (getClass().getName().equals(intent.getComponent().getClassName())) {
363b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // If we were launched directly from the OutgoingCallBroadcaster,
364b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // not one of its more privileged aliases, then make sure that
365b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            // only the non-privileged actions are allowed.
366b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            if (!Intent.ACTION_CALL.equals(intent.getAction())) {
367b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                Log.w(TAG, "Attempt to deliver non-CALL action; forcing to CALL");
368b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                intent.setAction(Intent.ACTION_CALL);
369b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
370b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
3715398ca30f57b928c2dd9bf175c5e083726279494Nicolas Catania
372a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // Check whether or not this is an emergency number, in order to
373a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // enforce the restriction that only the CALL_PRIVILEGED and
374a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // CALL_EMERGENCY intents are allowed to make emergency calls.
375a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        //
376a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // (Note that the ACTION_CALL check below depends on the result of
377a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // isPotentialLocalEmergencyNumber() rather than just plain
378a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // isLocalEmergencyNumber(), to be 100% certain that we *don't*
379a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // allow 3rd party apps to make emergency calls by passing in an
380a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // "invalid" number like "9111234" that isn't technically an
381a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // emergency number but might still result in an emergency call
382a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        // with some networks.)
383a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        final boolean isExactEmergencyNumber =
384a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                (number != null) && PhoneNumberUtils.isLocalEmergencyNumber(number, this);
385a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        final boolean isPotentialEmergencyNumber =
386a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                (number != null) && PhoneNumberUtils.isPotentialLocalEmergencyNumber(number, this);
387a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        if (VDBG) {
388a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            Log.v(TAG, "- Checking restrictions for number '" + number + "':");
389a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            Log.v(TAG, "    isExactEmergencyNumber     = " + isExactEmergencyNumber);
390a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            Log.v(TAG, "    isPotentialEmergencyNumber = " + isPotentialEmergencyNumber);
391a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown        }
392a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown
393b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        /* Change CALL_PRIVILEGED into CALL or CALL_EMERGENCY as needed. */
394e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania        // TODO: This code is redundant with some code in InCallScreen: refactor.
395b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (Intent.ACTION_CALL_PRIVILEGED.equals(action)) {
396a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            // We're handling a CALL_PRIVILEGED intent, so we know this request came
397a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            // from a trusted source (like the built-in dialer.)  So even a number
398a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            // that's *potentially* an emergency number can safely be promoted to
399a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            // CALL_EMERGENCY (since we *should* allow you to dial "91112345" from
400a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            // the dialer if you really want to.)
401a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            action = isPotentialEmergencyNumber
402b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    ? Intent.ACTION_CALL_EMERGENCY
403b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                    : Intent.ACTION_CALL;
40408cd080c56979c22092ee611a416adb86618f868David Brown            if (DBG) Log.v(TAG, "- updating action from CALL_PRIVILEGED to " + action);
405b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            intent.setAction(action);
406b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
407b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
408b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (Intent.ACTION_CALL.equals(action)) {
409a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            if (isPotentialEmergencyNumber) {
410a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                Log.w(TAG, "Cannot call potential emergency number '" + number
411a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                        + "' with CALL Intent " + intent + ".");
412a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                Log.i(TAG, "Launching default dialer instead...");
413e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania
414e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                Intent invokeFrameworkDialer = new Intent();
415e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania
416e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                // TwelveKeyDialer is in a tab so we really want
417e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                // DialtactsActivity.  Build the intent 'manually' to
418e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                // use the java resolver to find the dialer class (as
419e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                // opposed to a Context which look up known android
420e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                // packages only)
421e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                invokeFrameworkDialer.setClassName("com.android.contacts",
422e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                                                   "com.android.contacts.DialtactsActivity");
423e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                invokeFrameworkDialer.setAction(Intent.ACTION_DIAL);
424e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                invokeFrameworkDialer.setData(intent.getData());
4256b0efb615a5b1a65984192384c88965fa7dd06a0David Brown
4266b0efb615a5b1a65984192384c88965fa7dd06a0David Brown                if (DBG) Log.v(TAG, "onCreate(): calling startActivity for Dialer: "
4276b0efb615a5b1a65984192384c88965fa7dd06a0David Brown                               + invokeFrameworkDialer);
428e9d36b8a17aadd2271db030fc13d0fef01ded7c2Nicolas Catania                startActivity(invokeFrameworkDialer);
429b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                finish();
430b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return;
431b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
432b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            callNow = false;
433b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {
434325cc2ced6f1ff5fb1708abfcc5e9c73ac0cd962David Brown            // ACTION_CALL_EMERGENCY case: this is either a CALL_PRIVILEGED
435325cc2ced6f1ff5fb1708abfcc5e9c73ac0cd962David Brown            // intent that we just turned into a CALL_EMERGENCY intent (see
436325cc2ced6f1ff5fb1708abfcc5e9c73ac0cd962David Brown            // above), or else it really is an CALL_EMERGENCY intent that
437325cc2ced6f1ff5fb1708abfcc5e9c73ac0cd962David Brown            // came directly from some other app (e.g. the EmergencyDialer
438325cc2ced6f1ff5fb1708abfcc5e9c73ac0cd962David Brown            // activity built in to the Phone app.)
439a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            // Make sure it's at least *possible* that this is really an
440a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            // emergency number.
441a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown            if (!isPotentialEmergencyNumber) {
442a42348fcc3a76ab0db9b710ee40042a73a0b9dacDavid Brown                Log.w(TAG, "Cannot call non-potential-emergency number " + number
443b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                        + " with EMERGENCY_CALL Intent " + intent + ".");
444b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                finish();
445b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project                return;
446b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            }
447b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            callNow = true;
448b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        } else {
449b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            Log.e(TAG, "Unhandled Intent " + intent + ".");
450b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            finish();
451b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project            return;
452b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
453b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
454b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Make sure the screen is turned on.  This is probably the right
455b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // thing to do, and more importantly it works around an issue in the
456b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // activity manager where we will not launch activities consistently
457b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // when the screen is off (since it is trying to keep them paused
458b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // and has...  issues).
459b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        //
460b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // Also, this ensures the device stays awake while doing the following
461b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // broadcast; technically we should be holding a wake lock here
462b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        // as well.
463b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        PhoneApp.getInstance().wakeUpScreen();
4645398ca30f57b928c2dd9bf175c5e083726279494Nicolas Catania
465b1545c869ff7fa76ce3c3256b23e1b2b4411f483Daisuke Miyakawa        // If number is null, we're probably trying to call a non-existent voicemail number,
466b1545c869ff7fa76ce3c3256b23e1b2b4411f483Daisuke Miyakawa        // send an empty flash or something else is fishy.  Whatever the problem, there's no
467b1545c869ff7fa76ce3c3256b23e1b2b4411f483Daisuke Miyakawa        // number, so there's no point in allowing apps to modify the number.
468008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman        if (number == null || TextUtils.isEmpty(number)) {
469008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman            if (intent.getBooleanExtra(EXTRA_SEND_EMPTY_FLASH, false)) {
4707291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown                Log.i(TAG, "onCreate: SEND_EMPTY_FLASH...");
4718343169cc89621d46dce86449f5ee1ff5d3a4919John Wang                PhoneUtils.sendEmptyFlash(PhoneApp.getPhone());
472008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman                finish();
473008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman                return;
474008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman            } else {
4757291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown                Log.i(TAG, "onCreate: null or empty number, setting callNow=true...");
476008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman                callNow = true;
477008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman            }
478008791ca2a9a1406c2a9f7b39c794104d151b898Paul Berman        }
479b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
480b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        if (callNow) {
48158e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // This is a special kind of call (most likely an emergency number)
48258e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // that 3rd parties aren't allowed to intercept or affect in any way.
48358e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // So initiate the outgoing call immediately.
48458e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown
48558e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            if (DBG) Log.v(TAG, "onCreate(): callNow case! Calling placeCall(): " + intent);
48658e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown
48758e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // Initiate the outgoing call, and simultaneously launch the
48858e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // InCallScreen to display the in-call UI:
48958e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            PhoneApp.getInstance().callController.placeCall(intent);
49058e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown
49158e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // Note we do *not* "return" here, but instead continue and
49258e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // send the ACTION_NEW_OUTGOING_CALL broadcast like for any
49358e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // other outgoing call.  (But when the broadcast finally
49458e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // reaches the OutgoingCallReceiver, we'll know not to
49558e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // initiate the call again because of the presence of the
49658e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // EXTRA_ALREADY_CALLED extra.)
497b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        }
498b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project
499919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa        // Remember the call origin so that users will be able to see an appropriate screen
500919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa        // after the phone call. This should affect both phone calls and SIP calls.
501919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa        final String callOrigin = intent.getStringExtra(PhoneApp.EXTRA_CALL_ORIGIN);
502919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa        if (callOrigin != null) {
503919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa            if (DBG) Log.v(TAG, "Call origin is passed (" + callOrigin + ")");
504919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa            PhoneApp.getInstance().setLatestActiveCallOrigin(callOrigin);
505919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa        } else {
506919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa            if (DBG) Log.v(TAG, "Call origin is not passed. Reset current one.");
507b1545c869ff7fa76ce3c3256b23e1b2b4411f483Daisuke Miyakawa            PhoneApp.getInstance().resetLatestActiveCallOrigin();
508919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa        }
509919b11dcec9c7a80121e6cb4b9e624f59da43d55Daisuke Miyakawa
5101e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // For now, SIP calls will be processed directly without a
5111e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // NEW_OUTGOING_CALL broadcast.
5121e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        //
5131e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // TODO: In the future, though, 3rd party apps *should* be allowed to
5141e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // intercept outgoing calls to SIP addresses as well.  To do this, we should
5151e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // (1) update the NEW_OUTGOING_CALL intent documentation to explain this
5161e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // case, and (2) pass the outgoing SIP address by *not* overloading the
5171e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // EXTRA_PHONE_NUMBER extra, but instead using a new separate extra to hold
5181e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // the outgoing SIP address.  (Be sure to document whether it's a URI or just
5191e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        // a plain address, whether it could be a tel: URI, etc.)
5201e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        Uri uri = intent.getData();
5211e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        String scheme = uri.getScheme();
52265454c803eb305c4740885ad4995a871b034a58aDavid Brown        if (Constants.SCHEME_SIP.equals(scheme)
52365454c803eb305c4740885ad4995a871b034a58aDavid Brown                || PhoneNumberUtils.isUriNumber(number)) {
5248ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown            startSipCallOptionHandler(this, intent, uri, number);
5251e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang            finish();
5261e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang            return;
52758e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown
52858e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // TODO: if there's ever a way for SIP calls to trigger a
52958e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // "callNow=true" case (see above), we'll need to handle that
53058e4707b6cc021a663deae3e614364545ec9ee6aDavid Brown            // case here too (most likely by just doing nothing at all.)
5311e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        }
5321e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang
533b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
5345398ca30f57b928c2dd9bf175c5e083726279494Nicolas Catania        if (number != null) {
5355398ca30f57b928c2dd9bf175c5e083726279494Nicolas Catania            broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
5365398ca30f57b928c2dd9bf175c5e083726279494Nicolas Catania        }
537d94cc5e209bf871e4b6d5e84bcf6bd4e38d8ac65Nicolas Catania        PhoneUtils.checkAndCopyPhoneProviderExtras(intent, broadcastIntent);
538b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project        broadcastIntent.putExtra(EXTRA_ALREADY_CALLED, callNow);
5391e5cdee4e88ac385e0049876d192d5659a71e4a6Chung-yih Wang        broadcastIntent.putExtra(EXTRA_ORIGINAL_URI, uri.toString());
54008cd080c56979c22092ee611a416adb86618f868David Brown        if (DBG) Log.v(TAG, "Broadcasting intent: " + broadcastIntent + ".");
5412587d9c6437b680911e252efecc73788e876de76Chung-yih Wang        sendOrderedBroadcast(broadcastIntent, PERMISSION, new OutgoingCallReceiver(),
5428ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown                             null,  // scheduler
5438ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown                             Activity.RESULT_OK,  // initialCode
5448ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown                             number,  // initialData: initial value for the result data
5458ffe7a03a21441fa6d1f3c96a82c68f4ee8900ddDavid Brown                             null);  // initialExtras
546b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project    }
5477291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown
5486c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    @Override
5496c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    protected void onStop() {
5506c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // Clean up (and dismiss if necessary) any managed dialogs.
5516c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
5526c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // We don't do this in onPause() since we can be paused/resumed
5536c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // due to orientation changes (in which case we don't want to
5546c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // disturb the dialog), but we *do* need it here in onStop() to be
5556c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // sure we clean up if the user hits HOME while the dialog is up.
5566c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
5576c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // Note it's safe to call removeDialog() even if there's no dialog
5586c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // associated with that ID.
5596c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        removeDialog(DIALOG_NOT_VOICE_CAPABLE);
5606c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
5616c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        super.onStop();
5626c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    }
5636c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
5646c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    /**
5656c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown     * Handle the specified CALL or CALL_* intent on a non-voice-capable
5666c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown     * device.
5676c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown     *
5686c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown     * This method may launch a different intent (if there's some useful
5696c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown     * alternative action to take), or otherwise display an error dialog,
5706c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown     * and in either case will finish() the current activity when done.
5716c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown     */
5726c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    private void handleNonVoiceCapable(Intent intent) {
5736c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        if (DBG) Log.v(TAG, "handleNonVoiceCapable: handling " + intent
5746c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                       + " on non-voice-capable device...");
5756c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        String action = intent.getAction();
5766c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        Uri uri = intent.getData();
5776c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        String scheme = uri.getScheme();
5786c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
5796c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // Handle one special case: If this is a regular CALL to a tel: URI,
5806c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // bring up a UI letting you do something useful with the phone number
5816c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // (like "Add to contacts" if it isn't a contact yet.)
5826c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
5836c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // This UI is provided by the contacts app in response to a DIAL
5846c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // intent, so we bring it up here by demoting this CALL to a DIAL and
5856c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // relaunching.
5866c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        //
5876c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // TODO: it's strange and unintuitive to manually launch a DIAL intent
5886c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // to do this; it would be cleaner to have some shared UI component
5896c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // that we could bring up directly.  (But for now at least, since both
5906c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // Contacts and Phone are built-in apps, this implementation is fine.)
5916c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
59265454c803eb305c4740885ad4995a871b034a58aDavid Brown        if (Intent.ACTION_CALL.equals(action) && (Constants.SCHEME_TEL.equals(scheme))) {
5936c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            Intent newIntent = new Intent(Intent.ACTION_DIAL, uri);
5946c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            if (DBG) Log.v(TAG, "- relaunching as a DIAL intent: " + newIntent);
5956c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            startActivity(newIntent);
5966c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            finish();
5976c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            return;
5986c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        }
5996c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
6006c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // In all other cases, just show a generic "voice calling not
6016c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // supported" dialog.
6026c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        showDialog(DIALOG_NOT_VOICE_CAPABLE);
6036c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // ...and we'll eventually finish() when the user dismisses
6046c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // or cancels the dialog.
6056c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    }
6066c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
6076c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    @Override
6086c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    protected Dialog onCreateDialog(int id) {
6096c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        Dialog dialog;
6106c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        switch(id) {
6116c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            case DIALOG_NOT_VOICE_CAPABLE:
6126c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                dialog = new AlertDialog.Builder(this)
6136c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                        .setTitle(R.string.not_voice_capable)
61450480073bf2394d5b065084f46b2223ab90fb7dcDaisuke Miyakawa                        .setIconAttribute(android.R.attr.alertDialogIcon)
6156c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                        .setPositiveButton(android.R.string.ok, this)
6166c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                        .setOnCancelListener(this)
6176c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                        .create();
6186c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                break;
6196c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown            default:
6206c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                Log.w(TAG, "onCreateDialog: unexpected ID " + id);
6216c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                dialog = null;
6226c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown                break;
6236c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        }
6246c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        return dialog;
6256c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    }
6266c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
6276c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    // DialogInterface.OnClickListener implementation
6286c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    public void onClick(DialogInterface dialog, int id) {
6296c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // DIALOG_NOT_VOICE_CAPABLE is the only dialog we ever use (so far
6306c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // at least), and its only button is "OK".
6316c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        finish();
6326c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    }
6336c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
6346c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    // DialogInterface.OnCancelListener implementation
6356c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    public void onCancel(DialogInterface dialog) {
6366c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // DIALOG_NOT_VOICE_CAPABLE is the only dialog we ever use (so far
6376c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        // at least), and canceling it is just like hitting "OK".
6386c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown        finish();
6396c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown    }
6406c5cf46a2a31f0bffe9df36da8922971f7ee296bDavid Brown
6417291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown    // Implement onConfigurationChanged() purely for debugging purposes,
6427291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown    // to make sure that the android:configChanges element in our manifest
6437291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown    // is working properly.
6447291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown    @Override
6457291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown    public void onConfigurationChanged(Configuration newConfig) {
6467291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown        super.onConfigurationChanged(newConfig);
6477291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown        if (DBG) Log.v(TAG, "onConfigurationChanged: newConfig = " + newConfig);
6487291a106eb69b365de60a9452c5fc31828e2db8eDavid Brown    }
649b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project}
650