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