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